{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# StackingClassifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An ensemble-learning meta-classifier for stacking."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> from mlxtend.classifier import StackingClassifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Overview"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Stacking is an ensemble learning technique to combine multiple classification models via a meta-classifier. The individual classification models are trained based on the complete training set; then, the meta-classifier is fitted based on the outputs -- meta-features -- of the individual classification models in the ensemble.\n",
    "The meta-classifier can either be trained on the predicted class labels or probabilities from the ensemble."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](./StackingClassifier_files/stackingclassification_overview.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The algorithm can be summarized as follows (source: [1]):\n",
    "    \n",
    "![](./StackingClassifier_files/stacking_algorithm.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### References\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [1] Tang, J., S. Alelyani, and H. Liu. \"[Data Classification: Algorithms and Applications.](https://books.google.com/books?id=nwQZCwAAQBAJ&lpg=PA500&dq=stacking%20classifier%20subsets&pg=PA499#v=onepage&q&f=false)\" Data Mining and Knowledge Discovery Series, CRC Press (2015): pp. 498-500.\n",
    "- [2] Wolpert, David H. \"[Stacked generalization.](http://www.sciencedirect.com/science/article/pii/S0893608005800231)\" Neural networks 5.2 (1992): 241-259."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 1 - Simple Stacked Classification"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from sklearn import datasets\n",
    "\n",
    "iris = datasets.load_iris()\n",
    "X, y = iris.data[:, 1:3], iris.target"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3-fold cross validation:\n",
      "\n",
      "Accuracy: 0.91 (+/- 0.01) [KNN]\n",
      "Accuracy: 0.91 (+/- 0.06) [Random Forest]\n",
      "Accuracy: 0.92 (+/- 0.03) [Naive Bayes]\n",
      "Accuracy: 0.95 (+/- 0.03) [StackingClassifier]\n"
     ]
    }
   ],
   "source": [
    "from sklearn import model_selection\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.naive_bayes import GaussianNB \n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from mlxtend.classifier import StackingClassifier\n",
    "import numpy as np\n",
    "\n",
    "clf1 = KNeighborsClassifier(n_neighbors=1)\n",
    "clf2 = RandomForestClassifier(random_state=1)\n",
    "clf3 = GaussianNB()\n",
    "lr = LogisticRegression()\n",
    "sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], \n",
    "                          meta_classifier=lr)\n",
    "\n",
    "print('3-fold cross validation:\\n')\n",
    "\n",
    "for clf, label in zip([clf1, clf2, clf3, sclf], \n",
    "                      ['KNN', \n",
    "                       'Random Forest', \n",
    "                       'Naive Bayes',\n",
    "                       'StackingClassifier']):\n",
    "\n",
    "    scores = model_selection.cross_val_score(clf, X, y, \n",
    "                                              cv=3, scoring='accuracy')\n",
    "    print(\"Accuracy: %0.2f (+/- %0.2f) [%s]\" \n",
    "          % (scores.mean(), scores.std(), label))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk0AAAHiCAYAAAD1WPj+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl8XFX9//HXJ1ubtEkbaOm+oEABQRYLCkhBka1QKD8K\nwhcorkVwBStVUVS+4PL9VhBF+LayllWpIIsCglBxAUrBQllaWqBL2nRJSZp9mzm/P+4knSQzyZ3k\nTmZ7Px+PPJrcuXPnzOi8+Zxzzz3XnHOIiIiISO/yUt0AERERkUygoklERETEBxVNIiIiIj6oaBIR\nERHxQUWTiIiIiA8qmkRERER8UNEkIiIZzcyON7OKVLdDsp+KJumVma03s89E/X2emVWb2XFm5szs\nL932v8fMfhz5/fjIPjd32+efZva5wWi/iKRGJDuazKzezLaa2Z1mNjzV7RqoSKY1RN5XvZnVDPLr\nq0BMIRVN4puZXQz8FjgN2BDZ/HEzO7qXpzUAF5nZ1OS2TkTS0Czn3HDgUOAw4Hspbk9QDnHODY/8\njEz0yWZWkIxGSfKpaBJfzOwS4JfAyc65f0c99D/Adb08tQa4E/hR8lonIunMObcVeAqveALAzE4z\ns/+YWa2ZbeoYoY48NjUyonOxmW00syozuyrq8eLIyFW1mb0FHBH9emZ2gJktM7MaM3vTzM6IeuxO\nM7vZzJ6IjBT9y8zGmtmvIsdbbWaH9ed9mtmXzWydmX1gZo+a2fiox5yZfdXM1gJrI9v2N7OnI/uv\nMbNzo/afaWZvmVmdmW02s/lmNgx4AhgfNdI1vkdDJGlUNIkflwLXACc451Z0e+xmYL/oU3gxXAec\nbWbTktVAEUlfZjYROBVYF7W5AZgLjMQbvb7UzGZ3e+ongWnACcDVZnZAZPuPgA9Hfk4GLo56rULg\nMeCvwF7A14F7u+XPucAPgFFAC/AC8Grk76XA9f14j58GfhY59ji80fgHuu02G/g4cGCkAHoauC/S\nzvOAm83swMi+twGXOOdKgYOAZ51zDXif45aoka4tibZV+k9Fk/hxIvAisCrGY014RdG18Z4c6WX+\nH17hJSK5409mVgdsArYTNeLsnFvmnFvlnAs7514H7geO6/b8nzjnmpxzrwGvAYdEtp8LXOec+8A5\ntwn4ddRzPgEMB37unGt1zj0LPA6cH7XPw865V5xzzcDDQLNzbolzLgT8Hu9UYm9ejYxi1ZhZx2tf\nANzunHvVOdeCdyryqG5TE34WaXMTcDqw3jl3h3Ou3Tn3H+CPwDmRfdvwiqsy51y1c+7VPtokg0BF\nk/hxKbAfcKuZWYzHbwXGmNmsXo7xC+BkMzukl31EJLvMjoyUHA/sjzeSA4CZfdzMnjOzHWa2C/hK\n9OMRW6N+b8QrhgDG4xViHTZE/T4e2OScC3d7fELU39uifm+K8XdfE9YPd86NjPx8I+p1O9vhnKsH\ndnZ73eg2T8GbE9pRfNXgFV5jI4+fDcwENpjZ383sqD7aJINARZP4sQ1vePxYvNNxXTjnWoGfAP8N\nxCqqcM7tBH4V2UdEcohz7u94cxsXRm2+D3gUmOScG4E3Gh0zP2KoBCZF/T056vctwCQzy+v2+OYE\nm52oLXiFEACR0297dntdF/X7JuDvUcXXyMjptksBnHMvO+fOxDt19yfgDzGOIYNMRZP4EjlvfgJw\nipndEGOXu4GhwCm9HOZ64GjggF72EZHs9CvgxKjR5lLgA+dcs5kdCfxXAsf6A/A9MyuPzJf6etRj\nL+GNSl1pZoVmdjwwi57zi4J2P/B5MzvUzIYAPwVecs6tj7P/43jzQS+KtLPQzI6ITGIvMrMLzGyE\nc64NqAU6Rs62AXua2Ygkvx+JQUWT+Oac2wh8GpiDN+Ex+rEQcDWwRy/Pr8W72i7uPiKSnZxzO4Al\neDkBcBlwTWTO09XsHknx4yd4p8Lex5vwfXfU67TiFUmnAlV4o+NznXOrB/oeeuOcewb4Id68pEq8\nSern9bJ/HXBSZJ8teKcifwEMiexyEbDezGrxTl1eEHnearwC7b3IaT1dPTeIzDmN9ImIiIj0RSNN\nIiIiIj6oaBIRERHxQUWTiIiIiA8qmkRERER8UNEkIiIi4kNS7rT8fM3zuiRPJIfMGDnD76KEaU/5\nJZJ7/GaYRppEREREfFDRJCIiIuKDiiYRERERH1Q0iYiIiPiQlIngItIPYShsLSQ/nI/5vtn74HE4\nQnkh2ora1N0Ska7SPL8gmAxT0SSSJgpbCxlWNAwrNMzSL3Scc7g2R0NrA21D21LdHBFJI+meXxBM\nhqm/KJIm8sP5aR04ZoYVGvnh/FQ3RUTSTLrnFwSTYSqaRNKEkd6BA5HQSdOhdxFJnUzILxh4hqlo\nEpFO/3z6n8w6bBYzD5nJrb+8NdXNERFJSLIzTEWTiAAQCoW47tvXcfNDN/PIy4/wxNIneHf1u6lu\nloiIL4ORYZoILpKBvjzjPBqrPuixvWTUHvzu+Qf6dcxVK1Yx+UOTmbT3JABOPftUnnv8OT68/4cH\n1FYRkWjJyC8YnAxT0SSSgRqrPuDFUeU9tn8iRhD5tb1yO2MnjO38e8yEMby+4vV+H09EJJZk5BcM\nTobp9JyIiIiIDyqaRASAvcbtxdbNWzv/3rZ5G2PGjUlhi0RE/BuMDFPRJCIAHPSxg9jw7gYq1lfQ\n1trGE398guNPOz7VzRIR8WUwMkxzmkQEgIKCAr6/8Pt8ZfZXCIVDnHXRWexzwD6pbpaIiC+DkWEq\nmkQyUMmoPWJOmiwZtceAjjvj5BnMOHnGgI4hItKbZOUXJD/D+iyazGwa8PuoTR8CrnbO/SpprRKR\nXg3kstxcovwSST+ZnF99Fk3OuTXAoQBmlg9sBh5OcrtERAZM+SUiQUp0IvgJwLvOuQ3JaIyISBIp\nv0RkQBItms4D7k9GQ0REkkz5JSID4rtoMrMi4AzgwTiPzzOzFWa24tE7Hw2qfdKLF595kflz53PB\n8Rcwf+58XnzmxVQ3SSQtKb/SkzJMMk0iV8+dCrzqnNsW60Hn3GJgMcDzNc+7ANomvXjxmRdZdMsi\nJs6byKHTDqV2TS2LblkEwCc+84kUt04k7Si/0owyTDJRIqfnzkdD22lj6ZKlTJw3kZEfGUleQR4j\nPzKSifMmsnTJ0lQ3TTLYDy/9IcftfRxnHXlWqpsSNOVXmlGGSdAGI798FU1mNgw4EXgoaS2RhFRu\nrKRsWlmXbWXTyti6cWucZ4j07cwLzuSWh29JdTMCpfxKT8owCdpg5Jevosk51+Cc29M5tyuprRHf\nxk0eR+2a2i7batfUMnby2DjPkGxUXVXNZWdfQc3OmkCON/2T0xlRPiKQY6UL5Vd6UoZJJuaX7j2X\noebMnUPF4gpq3qwh3B6m5s0aKhZXMGfunLjPyZVJl7nyPgGW3vkYq1Y08+AdmrwsmSXRDMuV73Wu\nvE/IzPzSbVQyVMdEyaVLlvL+xvcZO3ksl1x6SdwJlLky6TJX3id4vbRH7/sXe465mUfvu4xzPn8G\nI/ccmepmifiSSIblyvc6V94nZG5+qWjKYJ/4zCd8f5GiJ10C3r/zvO3xQmrpkqVUbqxk3ORxzJk7\nJyO+tIm+z0y29M7HaG+fRcnw/aitmcWDdzzKl+fPTXWzRHzzm2H9+V5nYoYpv9I/v3R6LkckMumy\no7dTfEExh955KMUXFLPolkUZMUycK5NLO3ppJcMvAKBk+AU8et+/ApsbIJJOEv1eZ2qGKb/SP79U\nNOWIRCZdZvKlwLkyubSjl1ZQMAqAgoJRtLfPGvDcgCs/fyUXnnAh69eu54RpJ/DQXbrgTFIv0e91\npmaY8iv980un53LEnLlzvHPj87yeS+2aWioWV3DJpZf02LdyYyWHTju0y7ayaWW8v/H9wWpuvyXy\nPjPZi8+tINS+k+qq+7tt33NAQ9z/c8f/DLRpIoFL9HudqRmm/Er//FLRlCMSmXTZ0dvpOK8OmdPb\nSXSCfKa67c+/TnUTRAZNot/rTM0w5Vf6U9GUQ/xOusyW3o5Dd8MQyRaJXPiSDRmm/EpPKpqkh0zu\n7eTSJbsiElumZpjyK/2Zc8FXs7rhpaTK/LnzKb6guMuwfM2bNTTd28TCJQtT2LK+FTcWU1xWnOpm\n9KmptommkqYu22aMnGEpak7glF+SKsqvwTGQDNNIk2TkeibxZOoEUBHpH+WXDCYtOZDjMnU9k3hy\n5ZJdEVF+yeBT0ZTjMnU9k3j6c08+2W1rxVa+MPMLnDn9TGYfMZt7br4n1U0SiUv5JdEGI790ei7H\nZdtwcKZOAE0X+QX5zP/pfA489EAa6hr47LGf5ahPH8WH9/9wqpsm0oPyS6INRn6paMpxmbqeSW8S\nuTQ5k/3j6X9w9513s2XDFsZPGc9Fn7uIY088dkDHHD12NKPHjgZgWOkw9p62N9u2bFPRJGlJ+ZW5\nMjW/VDTlkFgTJuOtZ3L8Ucczf+78tJhcmU0TPYPyj6f/wfW/vZ5JX57EYfsfxq7Vu7j+t9cDDDh4\nOmzesJnVr6/mo9M/GsjxRAYikfy65NJL0iY30qUd6SST88vXnCYzG2lmS81stZm9bWZHBdoKSbp4\nEyYBLrn0EprubeK1z71G071NHH/U8Sx7YVlaTK7MtomeQbn7zruZ9OVJlB9UTl5BHuUHlTPpy5O4\n+867Azl+Y30jl194OQt+voDhZcMDOWaqKL8yXyL51bGAZTrkhvIrtkzOL78jTTcCTzrn5phZEVAS\naCsk6aInTALev/O87QuXLOzS85k/d37cfeP1kOL1pgbay+qt3bncW9uyYQuH7X9Yl20j9h/Bexve\nG/Cx29rauPzCyznt3NP4zJmfGfDx0oDyK8Mlkl+QeIYpvwZXJudXn0WTmY0AZgCfA3DOtQKtgbdE\nkiqRCZOJTq6Mt4rtmpVrWPbCsgGtbpttEz2DMn7KeHat3kX5QeWd23at3sX4KeMHdFznHD/66o/4\n0LQPcfHXLx5oM1NO+ZUdEs2BRPZXfg2+TM4vP6fn9gZ2AHeY2X/M7FYzG5aU1kjSJLL+R6JrhcS7\n7PfhBx4e8OXAWrcktos+dxGbfreJ6jeqCbeHqX6jmk2/28RFn7toQMf9zwv/4bH7H+Olv7/EnKPn\nMOfoOTz/1PMBtTollF9ZINEcSGR/5dfgy+T88nN6rgA4HPi6c+4lM7sR+C7ww+idzGweMA/g2zd8\nmzM+d0agDZWBSeQGlnPmzuHG62+k9JxSCicW0lbRRt2DdXzzim/GPHblxkrGV43npW+/RNPmJoon\nFDPljCk01jVSNq2sy76J9rKy4cabydAxWfLuO+/mvQ3vMX7KeK746hUDnkR5+NGHs6puVRBNTBfK\nryyQaA4kkmHKr8GXyfnlp2iqACqccy9F/l6KFzpdOOcWA4tB925KR4mu/xFuClO1tIrWXa0UjSii\nsKkw7rGLi4t55953mPDVCQzbbxgN7zTwzm/foTC/cMCXA2vdkviOPfHYwK40yWLKryzQnxzwm2HK\nr9TI1Pzqs2hyzm01s01mNs05twY4AXgr+U2TDkFdsup3/Y+lS5YyZNoQdi3fRXtDO+2N7ex15F5x\nJy9avjHqrFEU712M5RvFexcz6uxRNN/dTMXiigH3snJl3RIJnvIrPQSRYYnkQCIZpvySRPi9eu7r\nwL2RK0/eAz6fvCZJtHiTFMH/ZMRErVmxhvbydiZdNYlhBw2j4Y0GKq6voLq6Oub+jfWN7Hvkvuz6\nYBctrS0UFhUy6chJrLt7HZdceol6WZJqyq8USvcMU35JInwVTc65lcD0JLdFYkjFJautrpXJl0+m\n9LBSAEoPK2Xi5RPZ+MONMfcfN3kcoS0hJn5kYue2mjdrGDt5rHpZCXA4nHOYWaqbEpdzDkdmnb1S\nfqVWumeY8isYmZBfMPAM04rgaS4Vl6yGQ2GKpxXjwg7LM1zYUTytmHAoHHP/3iZd3rXwLh5+4GEa\n6xopKS3hrPPO4uL5mX8pezKE8kK4NgeFpGXwOOdwbY5QXijVTZEMku4ZpvwKRrrnFwSTYSqa0lwq\n7q00rGwYzWuaGXbQMEIuRJ7leX+Xxb9SO9aky7/98W/8e9W/mfS9SZQeXErdqjr+cMMfABQ8MbQV\ntdHQ2kB+cz5G+oWOwwubtqK2VDdFMkgmZJjya+DSPb8gmAwz54IfatfVJ8GJng8QazJiIpMr4/Wa\nuk/SLB9W7oXF5bvDYtMNmzh39rlMO3Raj9dcumQpxRcUdwnFmjdrWP6t5ex97d6UHb77st3aV2vZ\n+rOtfPfn39X9mLLIjJEz0jMl+0H5FaygMsxvfs2ZO4c1K9fwhz/9wVeG1eyoYdy3xim/cpzfDNNI\nU5qLd8kqkNDkyrsW3uWFSLdeU8W7Fazbvq7LcdYtXsfRBx/Nyz97mffq3qOktIRzz/PCJtZr1q6v\n5RPTur5m2bQy2tvaKT24tMv20oNLeXfXu4M+MVREUiOIDEskvxbdsohLLr2EczmXh3/2cJ8Z9vaP\n36a8qrzL6ym/JB6NNGWo+XPnxxzdabq3iYVLFvbYf/b02Yz93tgevab3f/A+R/7qSF/Hifeaq65a\nxcHXHey7p5bIa0pm0EiTJCqRDAsiv+K95pqn11C1tIpjFh3T5RjKr9ziN8P83EZF0lDlxsqYq9Vu\n3bg15v6NdY0xe03tbe0xj7NmxRpmT5/NSdNOYvb02dy18C4qN1aSPz6fivUVvP/O+1SsryB/fD4F\n+QVULK6g5s0awu1hat6soWJxBTOOn8GmGzZR+2otrs1R+2otm27YxJCCIQm1XUSyTyIZlmh+bd24\nlbsW3uUrw/b8yJ40vN+g/BJfdHouQyU6ubKktIS6VXVdek11q+ooKCzocZxVP19F+4h2Jsyf0GUo\nvLitmE3LNzHyqJGUDC0h1Bxi0wubKB9dzhcv/WLM9UzuWnhXjyHyVa+vGvSJoSKSXhLJsETyq3ZN\nLaHWUMzTebEybPsL2xm11yia7m1SfkmfdHouQ/U2ubLXOU3dJkYeffDRnXMCOo7z4jdfZO9r92bk\nx6JC4dVa1l25juKpxYz+r9EUTSqidVMrO+7bwZiiMdz6xK0Jtf2G626graRt99UqjYVcftXlmhOQ\noXR6ThKVSIYlkl8ViyvYsW4HE6+e2OPUWhAZpvzKTpoInuUSvadRxyWy3XtN0VefdByHMIz46Igu\nzy89uJRQe4hwW5gdf9xB+652CkYUEG4LU10Te6Xw3uQV5zFqzqgu66KISO5IJMMSya9LLr2Eq796\ndczTeUFlmPIrd2mkSXqIN+ly3ffWsc/P9ol5Ce6fVvzJ9/ETncQu6U8jTZJOkplhyq/spJGmHDbQ\nm2Oedd5Z/OGGnkPhQ4uGUlBeQKgpRP7QfELNIQrKCyjIL0joNVOxQrCIZIYgbu6baIa5kGP+3PnK\nL+mTiqYsE8TNMeMNha96fRXUQKgo1Hljy6E1QykfXZ7Qa6ZihWARSX9B3dw3kQyzrUY77RRfUKz8\nkj5pyYEsE31zzLyCPEZ+ZCQT501k6ZKlAz72nLlz2HnvToY3DGfKh6YwvGE4O+/diQu5hF5zztw5\nMZcomDN3zoDbKCKZK5n5BbEzbMMtG5h6/lTll/iikaYsE8TQcbzVd8/lXC659JIeky5/c+1vYq5b\nEu81E53ELiK5IahTX4lkWGFjIVPPner7NZVfuU1FU5YJYuj44QceZtL3JnVOliw7vIxJl0/i4Z89\nzJ/m/6lHOCxdsjTh1/zEZz6hkBGRLoI69ZVIhs2fO1/5Jb6paMoyc+bO4RdX/4K2kjbaa9spKCug\nsLGQBdcsiHvDy+4a6xoJNYR458p3aK1spWhcEaNnjaaxrjHmJM05c+dw4/U3UnpOaZdLcL95xTdT\n8AmISKYKIr8gsQw7+KMH8+SNTyq/xBdfRZOZrQfqgBDQ7pybnsxGSf+tWbmGFlrY67NjGDKpiJZN\nrWy/YxsP3PQAa6vW9hiuBnoET2F+IZX3VTLhaxMo2a+Exnca2XzTZvLIizlJ8/ijjifcFKZqadXu\nxd6aClPx9kV6UH5ljiDyCxLLsCdvfJKm7U20LG1RfkmffK3TFAmd6c65Kj8H1TonuwVx+WwiPazZ\n02cz5ntjGHpACWZFONdK89uNvPu9d32vT3LB8RdQeH4hZceUkTckj3BLmNp/1bLt19uYfv103zfs\n1boluSOd12lSfvVfEPkF/jMsiPyCxDIs3g17lV+5Res0pYEgLp+NN6ERYvewGusaKdl/GGHyAAPy\nKdl/GC7kYq6Q+17dewAsf3n39pYWGPeRcdRvrsG5MGZ5jPrIOLa0b4k54buxrjGhieAikv6Cuvw/\nkQzrLb+GfaSUcHj3vsM+UkpD7XtdsqtDvAzb3LaFgkllNDbu3rdgfCEtNa1dt00qY/3a92Me+8gj\nfL/1wMRqhwRrxon+9vNbNDngGTMLAYucc4v72a6cEn35LOD9O8/b7jd0epvQGKtoKh5eTO2qWkoP\nGQWAWQG1r1dh+RbzhpclpSWdX8hpzTMAmDj6AAq3QcHwNsibDG4jhduGUVRcwvbXaik7IGrC5Nu1\nlJSWDPq6JR1tTkWAScZRfvVDEPkFiWVYb/lV/0Y9Iw7dnTG73qihpKSsM7eixcuwkpIyWta0M/KA\nPTv3bd8UpqismCHh3Z3KmjU7mTh6/x7HXjP0eZa/PLi5s/xlmPb80MF7wVwVcNH0SefcZjPbC3ja\nzFY7556P3sHM5gHzAL59w7c543NnJNDa7BTE5bONdY3eCJGDttY2CosKu4wQdffhyfvx1g1vMPaL\nYYZMKaJlQytbb6tk1PC92PjLjYz5whiGTB5Cy8YWtt2+jWOO/WyPY5xxwuX8+oaLGXH+SIZObaF5\nfRMV969n1rHf4t+Lf0/BF4bQVFZLcW0Zm++o4Ihjz+LN3yxjwpdh+L5l1K+tpWqJd+PN/vDbq5rW\nPIPlLz/f9459UOGV9ZRf/RDU5f+JZFi8/Cot2otNv9xI6xdaGDK5iJaNrWy7fRtnHvudmK8ZL8Nm\nHvs1/n3r73FfCHVmWO0DjRQ2DaXm7Z2U7VtO7dpqNt+6kYtP6nlqblrzDNYMHXjm9MesI7el5HWl\nK19Fk3Nuc+Tf7Wb2MHAk8Hy3fRYDi0FzAjokcvlsvEKhqLiEXa/XMezgYYTD0NYWomFVA0XFJTFH\nW2qqGgg3hNnxwDZC9SHyh+cTbghDYQFDGMKO3+/ovCplCEM44bRpHHmE9/odYbCu7SUadzXQ9hCE\n6reTP7yItl0N2NQwF++zkFv/93K279jMXqMn8KXzb+Jjh5/KK68+waO33cDq7WsoHTuST518CXkj\nPtHvYeVYvceB7BdPR89RBsbv0HYqKL/6J9HL/weSYR22bGog3Bwjv8IFFISL2PH77bTXtVNQ6v1d\nfODQmEVMvAybMH5ajwybd/7NADx6xw28v30FY/aaysUnLeRjh58a97NJJDNidcp6e746cemtz6LJ\nzIYBec65usjvJwHXJL1lWWDO3DneHIB5Xg+tdk0tFYt7jsAsfzn+f/xnHfstHr1+IWO/MY5hB5ZT\n+3o1W39dyRnHzo/Z69lj7xIm/ODImJO1J8yewI4VO6irq6OkvITRJ47uHGqP/qL++jt3ssdnxtO4\nrpFwfSv5JYWUfmY8Ty+9k1N/8DWoH8+44Y8Qqr+Uffc5EoCPHX4q++5zBDfccAmXf3kxZWV7QnNA\nH2QSDbTokvSm/Oo/v/kVLdb3qa8Mi1Y2sYR9L42dX5POjuRXfR0le5Qw+qTRvP7CUuZe2vNUYawM\nG/6Z8dz3yI/4xQ//2SPDysr23J1fl0TyK4H3GE9vo1KxjpOqUSzxz89I0xjgYTPr2P8+59yTSW1V\nlvCzcmxfPZbzzr2aN958gdVX/wsX3ojlFbL/xGM479yrY+4fa0i9YFIZdVX1bP7nFvb6whjGfmg8\nze81s/n2LYTX5/U4R79901aKiocw7kvjKN53L5rWNlF5ayXNW1t46qklhEKnU1w8jfr603nqqbs4\n55wrAHjqqSW88051l20iKab86qegVr4+bO7xLH/7z2y4+u3ODJsy+YCYGfbBtkomTDq0x6Ts+p31\nbPnXFsZ8YQxj9x5P6/vNbLl9C6H382KOuMfNsG0t3PO3n9AUPoE9umWY8kv86LNocs69BxwyCG3J\nSr2tHNt9AnYstbVV7NzewoTh75GfP4pQqIqd28+ltnZnzN5Qx5B60d67e2r1a2vJH1rAmLljGbrf\nUKCI4v2MMXPHsvXaHZ1t6QidkvISxn5pbOfEzaGHDyH/S3lUXFPJk8/9gYKSBwAoLp7Ls8+ey8kn\nXww4nn32ccrLb+HZZy/l5JMv7rW3JjIYlF8DM9CVr9cMfZ6GXTW07DImj3mdgoI9aW/fya5t58XM\nsImjD+gxUXvH2k3kDclnr7l7MWTfYsyKGLKvsdfcvdj839s683P5y8/3mWGVP63kzX+8zJDiB2i2\nus4MO/ro05Vf4otu2JtifQ31dozs5Od7V5N4hZPXO4rlo0fN4d3fVFD7dg2FrcNoerOV7YurGFo4\njLwReYRbwDkIt0DeiDwK8oqY1jyDhl01XHLyj9j1wS4K8gsoKC8g1BQCB6GmkPd3W4hQaBYAW7ac\nDVhnW556agltbadSVZVPW9upXdpXW1vFT35yNrW1O4P50EQkY2x+/WlC7bMoKPCKkIKCPQmFZsXM\nsDNOuJzNt26k5u2d3s1w397J9sVVFBUNJb8s38uvsJdf+WX55Od5/f7a2ipu+4GXX0D8DGsNEWqf\nRUkJVG2+kI4MW7RogfJLfEnKOk2aWBuclSuXEQptYdeu+7ptH985hBz9ee8//RNMbD2YR2+7gdei\nJjU+9NT/0PBOJUNCQ3CuEbNCWt5tY9zYfQF499F1bH7buPnav7LHuKnYdggXhWhpbSEvvxDbPpS8\n/CLyWx5m19bbaGoaybZtRzBs2B6sWLEntbVttLb+hubmEEVFM3n22a939tY07C2ZRPkVrBXLXiPU\n/hw1Vfd3bguHYOXKD/XIg47J190nZd/79FU0vlPP0NDQzvxqfreVUeMnAl7ncuPqdm6+9q+ccP45\nnRnWlh8DPvVcAAAgAElEQVSiua2F/EIvwxxFNDbezwc7FtHSNIpt246guLiMt95qoqTk2qTkV6L/\nf4q3/2PLxyT82uLfrFn+9vO1IniiHnsMXX2SoIFMAPQzMfFXN87jpY1/YdRF0xg6eRTNG6uounsN\nH588ky98/qd85ztnU119FeXl13HhRZdx37++z9gvjKOtrJnC2qHsvK2ai09ayL77HMGCBeeSn38L\nodCl/OIXD0ZGmkJUV5+B2RSc20B5+aOcfHI+J588t8f+GvbOPrNmkbYrgidK+RWcNUOfj3v1WCIT\nqhPJr//934dYu245d/11PuO/MKFzaYEtt2+OmWHHHPMpli0bqvzKcX4zTCuCp5H+XGrasVRAXwG0\nY/tW2jc5Nl+/HEcII5/85jJ2DN3KU08toa7uOFpbp1BXdxxbKzfzpRNv4tb/iV5a4AY+dvipPPjg\n9T0mgq9cuYyGhtWEQr8jL6+McLiWhgZYuXJ/gLgTx0VE/Egkv6IzpuvyKLEz7O9/X0JDQ6PyS3zR\nnKYM11Fo9TVStWDB7exRvg/UP01+4wdQ/zR7lO/DZZct5JlnHqG5eSYFBVNobp7JM888wtgxH45c\nlrsC6sez7z5HUltbxbPPPk5x8VygYyL441x22UJGjpzIlCn/ZurUFUyZ8m9GjpzIZZctjLm/5gaI\nSCISza/a2p3su88RvjIsL28EpaVjlF/ii4qmQTDQiYQvPvMi8+fO54LjL2D+3Pm8+MyLXR73Uzh1\n9MZgMu3tFcBk6uqOY9GiBdTVHYdzpbS1XYBzZZ3bW1pOoqKihZaWkzone8ealL5o0QJCodOBrhPE\nO7bHm8SuCZYi6S+I72n3DFu94sW+nxQl0fzqyCs/GVZXdxz19d7fyi/pi+Y0DYIHH7yeP/3pcWbP\nPj3u0G5HwdP9FF30TTO7LzAXb72nWKfqvvvdU1mz5g2cG0o43Exe3lDMmikqgtZWCIcLcK4cs2rM\nWigoGE5e3j00Nw9n6NB69tzzu5SVFVFV1fNG8Y2NVZSUjKKh4QOamkZSXFzDsGF7dG7vbuzY8Vx3\n3aO+PhfJDJrTlL0G8j1dM/R5wrt6Zti7v6ngSyfe1Ouq29ESya+8vHY+/OH9aGhw7Nz58z4zrKZm\nO9BGYWGx8iuHaU5TmugYDo61/kdtbZW3Au3li5nGjJg3g+zrppnPPVPDA/97A+ddeQWHF8Wf/v+x\nj51IVdVRVFcvIz//FuBSyss/xfjxr7Jly2FUVy8DvO1FRSU491EaG4uBCTQ3b6Sl5SSmTy/inHOu\n6NLu6PeyYMG5jBrlb8Jkb5+LiKQHv/nV23c3VoZN+DI8eps3x8jPcRLJr/LyT1FS8ioffPBxmpv9\nZZjyS/zS6bkk6xgOLiqa1mN9pehLWYGoRdp2P79yYyVl08q6HLNgUhnr125l+cu7lwp495G1vbZj\n5cpl1NffSSh0CM6FCIUOob7+Dtau/U+P7U1NL9HUdAcwG5gBzGbXrltYuXJZzHb39T4T/VxEJD0k\nkl/xrF9bScGkMhob6fwZvm8Z27av932cRPKrY/uuXbfgN8OUX+KXiqYkijdxurZ2Z7eeyu7Jhd0L\np44VvmF34NSvrWXi6P0Zt/3AmMeIZcGC2ykvn8qUKVcxdeqBTJlyFeXlU1m48K89to8evS95eSXA\nPZi9BNxDOFzIZZf9Mma7e3ufiX4uIpIe+pNf3U1rntG5yveQcGnnT8uadsbsNdX3cRLJr/Lyqfz4\nxw8QDhfiJ8M2b35H+SW+5f/4xz8O/KDvvEPwB81Ajz76f6xbtx9Dh54AQF5eCS0tO3HuNd599zXW\nrduP4uJZnds+8pGjABjVPoVR7VN4ffsG8vPLePme58gbV0RheRHNb7ex9XeVfPbEH7Hi5b/FPYbf\ntqxZcxt1dSeSl3cgGzacQ2npmVRVPUl7+zHA6ZiNBAqBaioqfk9dXU2P1+x4L7HeZ6z29Pa5xGu/\npLdp0/hJqtsQFOWXp7/51V1Z8Sj+8eCDFE0uoqh8KLvWfMDmWzcmlGGJ5Fd7ewsvvPBT6utPA2b2\nmWEdx1B+5Ta/GaaJ4El01VVnsHXrlh7bR43yVtAuKvpD5/3kWlvPjXse/ZVXn+DRv93Atu3rGbPX\nVM444fLOBdr8HiNeWzomO9bUVNLWNprCwh20tTXjTXfbC28wMgxUUVxcwB577NvjNeNNEO+YMOm3\nLfH2l/SnieDZJ6j8goFnWCL5NXLkOHbufJ9wuAgYRV8ZtnnzMZSWFpOX13WKr/Irt/jNMBVNKfDg\ng9fz9NMwfPjuKy7q66/nxBPxfRVGX8fwO0kTYPPmNXzta6cRCt1Efv7XOO20c1i+fDRFRedTUfF5\nJk68i9bWexk79h9s3XrsgNot2UlFU+4IIr/6Os7JJ8/td37ddNMT/Pvfj/H00yjDxDddPZfG/NxP\nbqDHSOR+SYsWfZdw+Cxgb8Lhs3j22fspLh5FZeUvCYdHU1l5OCNHjmPt2ipKSjYNqN0iktmCyK++\njgP0O78WLbqSUChEKLRFGSaB00hTFuq4fNbP/ZJ299LuxuwwnPsP+fkX8cMf/pZrr/0qZg/h3P/j\nN795ggkT9h3kdyKZQiNNEpQg8uumm54Awnz966cpw8QXvxmmq+ey0FNPLaGt7VSqqvJpazu1y+Ww\n3Vexje6lwVA6emsLF36FcPg8QqESwuHzWLToypS8FxHJLUHk16JFV0YeU4ZJsFQ0ZZmOy2FbW2fS\n3ByitXVml8thu69P8s47r+DcPcCJOHdI5N97qK+vBc4jHA4B5/HGG6vYvLn3taBERAYiqPxavfpl\n3nhjFcowCZrvosnM8s3sP2b2eDIblI3i3aMokXsX+T1GRy+toaGAgoIpNDQUdPbWamureOaZR2hr\n+27nTS3PPvtbjB37HfbZZxX77PMa++yziqKiC4EjcK4Qsyk4V6iemmQ05Vf/BZFffo8TRH6NHfsd\nRo4cTTh8njJMApfIRPBvAm8DZX3tKF3Fm5SdyGRtv8dYuXIZDQ2rCYV+R15eGeFwLQ0NsHLl/gDU\n1R1Ha+uUzptaxpqM2da2GWjBuZnAcKAeaGTt2iEBfioig0r51U9B5Jff4wSRXwA7d27Cudtw7n6U\nYRIkXyNNZjYROA24NbnNyT7xVrz1uxJuosdYsOB2Ro6cyJQp/2bq1BVMmfJvRo6cyGWXLeSZZx6h\nuXkmBQVTaG6eyTPPPMKCBXdw220ruvzcffcqJkw4lL33fol99nmNvfd+ifHjD2DRolcG5TMTCZLy\nq/+CyK9EjnPZZQsHnF+33baCJUtWM378AcowCZzfkaZfAVcCpfF2MLN5wDyAyy5bxCmnzBt467JA\nxz2KiounUV9/emcvK972eMdoazuV6up8hg8/tddjAIRCpxMKtbFhwylMnHgXodDpLFq0gLq644Cp\nmA0Fpnb21rq/bsdx8/O9O3x7i8D13kaRNKb86qcg8qvjOH4ybNGiBQPOr+h2Z0WGLV8OwKwjt6W4\nIdku/g3vo/U50mRmpwPbnXO9lujOucXOuenOuekKHE+8exQlcq+jeBMj4x1jxYq/EgrdR2XldMLh\nrVRWHk4odB/vvPMKTU134NxMQqHpODeTpqY7eOWVp3u8pjfkfR+7dk3v/AmF7uu82aVIplB+9V8Q\n+RV9HD8Z9tZbb9HWtmRA+QXZl2EqmNKHn5GmY4AzzGwm3jWdZWZ2j3PuwuQ2LfPF6+109Kbi9YKi\nV/PuOTFyA0VFp8Y9xvTpcPTRp/H1r59GYeESnPt/XHPN/Z0r5HZfCfdjH+vZbt0KQLKI8qufgsiv\nsrI9E8qwPfa4hI9/fAd//vOD/c4vUIZJ8iS0uKWZHQ/Md86d3tt+WhzO09f9krrruHfRgw9ez5/+\n9DizZ5/OypXLeO+91TQ10TkxsrgYoDXuMfLz83n99YMpLLyGtrar+ehHVxEKhXS/JEmaTFjcUvmV\nmCDy65xzruCqq85IKMOamnbS2HiR8qvD8uUaaRoMs2YFf+85hU7ydV8N9wc/+D+uvfYrvm+OuXnz\nmsgquP8gL28c4XAlzh2r1XAlqVQ0CcRezRuc7xvzKr9iUNE0OHwWTQktbumcW9ZX4MjAeEPZx1NV\n9X3a2j7V61B4LN4quP9FXt44gEjw/JfWJ5Gcp/xKvu759dRTd/U6Kbs75ZekO92wN410TJhsa/sU\nzc3VDBkCb731FqWl7/u+weTatf8BltPWdlu37YXJbLqI5LhY+fXss49TVlZEKFTlK8OUX5LuVDSl\nkY5eWn39c+Tn30J9/aWUl1/IyScP832Z7P33r+/Xa3efvCkikohY+VVY+CmmT1d+SfbQvefSyMqV\ny6ivv5NQ6BCcCxEKHUJ9/R2Dcpls93s6iYgkQvkluUBFUxpZsOB2ysunMmXKVUydeiBTplxFeflU\nFiy4I6mvm+jqviIi3Sm/JBeoaOqHRG9U6VciEyaDbEvH6xYVTevz9UQk8yUjw/qTX0G0Rfklg0lF\nUz8kayi4P6vYDrQt8Vb9VW9NJHslI8P6uwr3QNqSsfm1fLn/H0krmgieoK5DwZdy8skXBzbxMNFF\n2oJoS1bdo0lE+pSsDOvPIpMDbUsm55fWXspMGmlKUDoNBQfRlmy7R5MkkXrDWSGbMkz5JYNNI00J\n2D0U/AegYyj43EBHmwa7LVl/CwLpaQBFjnrHmS3bMkz5JYNNRVMCgh4Kjre2iJ81RzJ5WFoCMMDR\nHRU/uSnI3BhIfgXdFpHBoqIpAd5Q8Bbfq3P3JXoCZPTz421PZlskBVT4yCALMjcGkl9BtyXldIo6\nZyR0w16/dMPLvsW6sWVZ2Z5xt0uG6iNMs6bw8Xmzy0yg/Oqb8qsb3VQ38/nMMI00pUjH0HRx8TTq\n63cPScfbLhkgToGkMJVso/ySXKWiKQXiTYA8+ujT02aSpvgQo0hSgSTZTvkluUxFUwrEmwC5aNEC\nTYxMZyqSRJRfmr+U01Q0pUC8CZBr11ZRUrIpOyZGZgMVSSI9KL+UA7msz6LJzIYCzwNDIvsvdc79\nKNkNy2b9XTnXz2W80k8qkLKS8it4/V0bSRkm2cDPSFML8GnnXL2ZFQL/NLMnnHMvJrltEsXvZbzi\ngyZs5xLlV5pQhkk26LNoct6aBPWRPwsjP7okdxAl8353OUGjSDlL+ZUelGGSLXzde87M8s1sJbAd\neNo591KMfeaZ2QozW/Hkk4uDbmdOS6d7RWWEGPdFm3Xkti4/kjuUX6mnDJNs4WsiuHMuBBxqZiOB\nh83sIOfcG932WQwsBi0OF6R0uldU2tJIkvRC+ZVaGZthukpOYkjo6jnnXI2ZPQecArzR1/4ycLo/\nUzeajyT9pPxKjUzOMOWKdOfn6rnRQFskcIqBE4FfJL1lAmTZ/ZkS0UsvT0Emfim/Ui9nM0yykp+R\npnHAXWaWjzcH6g/OuceT2yzp0N/LezNCrtyXTVJJ+ZViWZ1hknP8XD33OnDYILRFckG3QkmFkSST\n8ktEgqQVwWVwRBVLKpRERCQTqWiS5NCIkoiIZBkVTRIsjSiJiEiWUtEkA6M1kkREJEeoaJL+0YiS\niKSjgBalVK5JLCqaxD/NUxKRDKBskmRR0SS904iSiKQr3epEBpmKJolNxZKIpLOom3GLDBYVTbKb\nTr+JaPQigyijZLCpaMp1GlES6ULfAxGJR0VTLtKIkoiISMJUNOUCraUkIiIyYINfNAU9X+DII4M9\nXqbq43NVkSQiIjIwySmaevkPeND/8X4sF4uwOO9ZhZGIiEjyJKVoGsz/eAf5Wo8tH5M+I2GDWHiK\niIhI3zSnKUrwo2D9L8JUGImIiKSXPosmM5sELAHGAA5Y7Jy7MdkNywYqfERSS/klIkHyM9LUDnzb\nOfeqmZUCr5jZ0865t5LcNhGRgVJ+iUhg8vrawTlX6Zx7NfJ7HfA2MCHZDRMRGSjll4gEKaE5TWY2\nFTgMeCnGY/OAeQCLLruMeaecEkDzJBt9+oorqN21q8f2shEjePb669P22JLZlF8SBOVXbvNdNJnZ\ncOCPwLecc7XdH3fOLQYWA/DYYy6oBkr2qd21ixUjRvTYPj1GWKTTsSVzKb8kKMqv3Nbn6TkAMyvE\nC5x7nXMPJbdJIiLBUX6JSFD6LJrMzIDbgLedcxofFJGMofwSkSD5GWk6BrgI+LSZrYz8zExyu0RE\ngqD8EpHA9DmnyTn3T8AGoS2SZeJNaqzYsYO3qqt7bA9iVatt1dUxj13R3s70L36xx3ZNsMxuyi/p\nL+WXxKIVwSVp4k1q3HPHDubG2L8tgNdsg7jH1gRLEfFL+SWxqGiSHuL1sCpraxlXVuZ7e0V1NcT4\nojugrb29y7atkX+796bUkxKRRCWSYduqq2kDJpaXd9meSH4BtNAzv0AZlm1UNEkP8XpYE3buTHh7\nLEXAa9b1jMl057gNOKTbcRLtSeWHw6woLOyxfWyMkBOR7JRIhr1VXc1ceo7kJJJfAGOdG/BokPIr\n/flackBEREQk12mkSXxrDIcZv25dj+1NCR6nBZjguq4fGALCwFvr13fZHm9y5Z5nnkmh67kGYSvw\nVktLj+2JrFYYxKq8WtlXJP3Ey7DmBI4RK7/Ay5ju+QWxMyzd8yvI42QbFU3i2xBgS4ztY+Psn5eX\nF3Noegiwqdu2I/CGPQ/Mz++yPdwWe3ploXNsjTNEvneM/Y3Yw+RlMYbTg1iVVyv7iqSfWBkWBsbH\n2DeR/CJyjO75BbEzLN3zK8jjZBsVTTkuVm/ivR07+OiOHT32bY1zjFZgeoweVkOc8/CteL21WBq7\n9bJCxJ5c2ZviIUN6bMtva2PFbbcldJzuKqqrNdFTJI3EGw1JJMM+E/m3e4YFkV+QeIYpv9KbiqYc\nF6s3MXbHDu6n5+I2nyb2qbgiYEmM7Z8m9mWyY3fsoKjbtjLgZGBit+2tvRwjFgdMD4V6bA/lDXz6\nXn44rJ6XSBqJNxoyZscOHoixf6wM2wU8BXSffp1IfoGXVTO6bXPEXi5A+ZW5VDRJD/nAh4Di7sPH\nzlEc5zkHTp3a8zjvvdfra0R7BpgArOj2mmNjnPfvjQErYrRFwSCSOww4MMbpr1gZ1rFX9wxLJL/A\n6zx2z68m59inj7Z2b4vyK72paEqBdJ9gFwLeA6xbwRKvfHHAazEmV/bsL8V3bOTf7hMs4w2DJ2qb\nhqZFApHu+QWRSdlxJmt31zFRu3uGJZJf4I00xZog3pjgcWJRfqUPFU0pkAkT7A6g53oURuxJ3wYc\nEqdXF4vDG1WKFgKeA6Z22x5rUiR4xVSsUagWYn+OiayoWzZiRMzteQkMkcc7RqyJmyKZJBPyy4AD\n42yPlWH7AiUxRtZjiZVf4J3e69l1jJ1h6Z5fvR0n1zNMRZMkZOujj/bYNvaMM2hK4DSaAZu7TXac\n0NLCVIh7+q+7D48endDEyFi9tDWbNlHZ1hZzFfJYx05kMqd6fyLpqXuGjT3jDAx8Z1is/AIY29LS\nI7/CcY4RRH5BYiNQiV5QowyLTUVTjovVm2gFDo2xb29Xzx0bY3vcXpMZE7pdhhvC68HFGspOVm8n\nFAoxLi+vRw8uXo9ZPS+R9BLvO9kKfDTG/rEyLIj86hDvVFz34wSVGeEEJncrv4KhoinHxepNTP/i\nFxMafo81ARIitxXw2ZuaMHs2JTFuHxDEpbZBUc9LJL3E+04mkmFB5Bekf4Ypv4Khokl62FZdzVvV\n1T23p6AtIiKJUoZJsqhoSoF0HyZtA+bG2R5v/0NizAeIt39MhYWxh7xj9Nz6I9ZnXhkOMy2g44vk\ninTPL0gswwLJL0hqhsX7zINYv0kS02fRZGa3A6cD251zByW/Sdkv3YdJJ5aXJ3R6bu/Rowd8Nc3m\nBx/038B+iHca8tk0CnpJDmVYsNI9vyCxDAsivyC5GdbbaUgZXH5Gmu4EbiL2os8iSe15JnNNmEzo\nMUsg7kQZJnFkan51HEcZNrj6LJqcc8+b2dTkN0UyVTJ7nslcEyYTeswycMow6U2m5hcow1JBJ0RF\nREREfAhsIriZzQPmASy67DLmnXJKUIeWQaYhX8k1yq/sogyTZAmsaHLOLQYWA/DYY4ndZVXSioZ8\nJdcov7KLMkySRafnRERERHzws+TA/cDxwCgzqwB+5JxL/fKmkhM0zC4DpQyTVFF+ZR9zCdxo1TcN\nb4vkllmzet6HIlMpv0Ryj88M0+k5ERERER9UNImIiIj4oKJJRERExAcVTSIiIiI+qGgSERER8UFF\nk4iIiIgPKppEREREfFDRJCIiIuKDiiYRERERH1Q0iYiIiPigoklERETEBxVNIiIiIj6oaBIRERHx\nQUWTiIiIiA8qmkRERER8UNEkIiIi4oOvosnMTjGzNWa2zsy+m+xGiYgERfklIkHps2gys3zgt8Cp\nwIHA+WZ2YLIbJiIyUMovEQmSn5GmI4F1zrn3nHOtwAPAmcltlohIIJRfIhIYP0XTBGBT1N8VkW0i\nIulO+SUigSkI6kBmNg+YF/nzHufcRUEdOx2Z2Tzn3OJUtyPZ9D6zS668z0TlWn5B7vx/Qe8zu6T6\nffoZadoMTIr6e2JkWxfOucXOuenOuenAAQG1L53N63uXrKD3mV1y5X12UH7Flyv/X9D7zC4pfZ9+\niqaXgX3NbG8zKwLOAx5NbrNERAKh/BKRwPR5es45125mXwOeAvKB251zbya9ZSIiA6T8EpEg+ZrT\n5Jz7C/CXBI6b9edVyY33CHqf2SZX3mcn5Vdcep/ZRe9zEJhzLpWvLyIiIpIRdBsVERERER8CLZrM\n7HYz225mbwR53HRiZpPM7Dkze8vM3jSzb6a6TclgZkPNbLmZvRZ5nz9JdZuSyczyzew/ZvZ4qtuS\nLGa23sxWmdlKM1uR6vakG+VX9lB+ZZ90ya9AT8+Z2QygHljinDsosAOnETMbB4xzzr1qZqXAK8Bs\n59xbKW5aoMzMgGHOuXozKwT+CXzTOfdiipuWFGZ2BTAdKHPOnZ7q9iSDma0HpjvnqlLdlnSk/Moe\nyq/sky75FehIk3PueeCDII+Zbpxzlc65VyO/1wFvk4UrDDtPfeTPwshPVk6AM7OJwGnAralui6SO\n8it7KL8kWTSnaQDMbCpwGPBSaluSHJEh35XAduBp51xWvk/gV8CVQDjVDUkyBzxjZq9EVsCWHKb8\nyhrKr0GkoqmfzGw48EfgW8652lS3JxmccyHn3KF4qygfaWZZd8rCzE4HtjvnXkl1WwbBJyP/e54K\nfDVyOkpykPIrOyi/Bp+Kpn6InCP/I3Cvc+6hVLcn2ZxzNcBzwCmpbksSHAOcETlf/gDwaTO7J7VN\nSg7n3ObIv9uBh4EjU9siSQXlV1ZRfg0yFU0JikwwvA142zl3farbkyxmNtrMRkZ+LwZOBFantlXB\nc859zzk30Tk3Fe8WG8865y5McbMCZ2bDIhN/MbNhwElA1l4lJrEpv7KL8mvwBb3kwP3AC8A0M6sw\nsy8Gefw0cQxwEV5FvzLyMzPVjUqCccBzZvY63v27nnbOZe3lrDlgDPBPM3sNWA782Tn3ZIrblFaU\nX1lF+ZVd0ia/tCK4iIiIiA86PSciIiLig4omERERER9UNImIiIj4oKJJRERExAcVTSIiIiI+qGgS\nERER8UFFk4iIiIgPKppymJl938x0Z2wRSVtmdqeZXRvnsf8zsx+muh0BHb/ezD4U+b3YzB4zs11m\n9qCZXWBmf03Wa4t/KpoymJmtN7PtkWXlO7Z9ycyW+Xm+c+6nzrkvJaFdy8ysORICu8zseTM7OOjX\nEZHUMrNPmtm/I9/zD8zsX2Z2hJl9zsz+mezXd859xTn330EcyzzfMLM3zKwhsir8g4OVXc654c65\n9yJ/zsFbBXtP59w5zrl7nXMnDUY7pHcqmjJfPvDNVDcihq8554YDewDLgLtT2xwRCZKZlQGPA7/B\n+55PAH4CtKSyXQNwI16WfgPv/ewH/Ak4LQVtmQK845xrH+iBzCw/gPZIhIqmzPe/wPyOm1N2Z2Y3\nmtkmM6s1s1fM7Niox37ccUdsM3vCzL7W7bmvmdn/i/y+v5k9HelNrjGzc/00zjkXwrv79oFRxz3S\nzF4wsxozqzSzm8ysKPLYb83sl93a8aiZXR75fbyZ/dHMdpjZ+2b2jW7HXRF5r9vMLGtvSCqSBvYD\ncM7d75wLOeeanHN/BdqA/wOOiow21wCY2Wlm9p/I93OTmf04+mBRo1Y1kcc/1/0FzazUzJ4zs19H\nRoY6T5mZ2fGR0aFvR0bgK83s81HP3TNyyqvWzF42s2s7RsPMbF/gq8D5zrlnnXMtzrnGyAjPz2O0\no9zMHo/kUHXk94lRj3/OzN4zs7pITl0Q2b6Pmf09MjJXZWa/j3qOizz+E+Bq4LORz++L3Ufuesvj\nyGdyi5n9xcwagE/5/59U+qKiKfOtwBvJmR/n8ZeBQ/F6TvcBD5rZ0Bj73Q+c3/GHmR2I19v5s3mn\n/56OPH8vvLtp3xzZp1eRYugC4MWozSHgcmAUcBRwAnBZ5LG7gPPNLC/y/FHAZ4D7ItseA17D69We\nAHzLzE6OPPdG4EbnXBnwYeAPfbVPRPrtHSBkZneZ2almVg7gnHsb+ArwQuSUU0eHrgGYC4zEG725\n1MxmA5jZFOAJvFGr0XiZtTL6xcxsT+BvwL+cc99wsW+cOhYYgZcPXwR+29Eu4LeRNowFLo78dDgB\nqHDOLff53vOAO/AycjLQBNwUaecw4NfAqc65UuDoqPfy38BfgXJgYuT9duGc+xHwU+D3kc/vtm6f\ng588/i/gOqAUSPpp0lyioik7XA183cxGd3/AOXePc26nc67dOfdLYAgwLcYxHgYOjYQXeIXOQ865\nFuB0YL1z7o7Icf4D/BE4p5c2/TrSw6wDvoY3bN/Rpleccy9GjrUeWAQcF3lsObALL8TAC4Rlzrlt\nwBHAaOfcNc651sj5/99F9gGvh7uPmY1yztU756ILNREJkHOuFvgk4PC+hzsio8Jj4uy/zDm3yjkX\ndkgf+20AACAASURBVM69jtdROy7y8H8Bz0RGrdoimRVdNI0H/g486Jz7QS/NagOuiRzjL0A9MM28\nU1RnAz+KjCC9hddB67AnUJnAe9/pnPtj5Fh1eAXKcVG7hIGDzKzYOVfpnHszqn1TgPHOuWbnXH8K\nGj95/Ihz7l+Rz7q5H68hcahoygLOuTfw5hZ8t/tjZjbfzN6ODAfX4PXCRsU4Rh3wZ3YXIOcD90Z+\nnwJ8PDJsXhM5zgV4PbZ4vhHpYRbjfcmXmtlHI23aLzKcvdXMavF6VdFtugu4MPL7heyeDzUFGN+t\nHd/HmzAJXs9yP2B1ZPj99F7aJyID5Jx72zn3OefcROAgvOLmV7H2NbOPR06t7TCzXXijUR3f+0nA\nu7281Gl4WfJ/fTRpZ7d5QI3AcLzRqwJgU9Rj0b/vBMb1cexOZlZiZovMbEMkw54HRppZvnOuAfgs\n3vurNLM/m9n+kadeCRiw3MzeNLMv+H3NKH7yeFPsp8pAqWjKHj8Cvow3LA2AefOXrgTOBcojRcwu\nvC9tLPfjnRo7ChgKPBfZvgn4u3NuZNTPcOfcpX01KtLT+QewDui4+uMWYDWwb+RU2ve7teke4Ewz\nOwQ4AG8yZkc73u/WjlLn3MzIa611zp2PN2T9C7xCbRgiknTOudXAnXjFU6xTZ/cBjwKTnHMj8Aqg\nju/9JrxT6vH8DngS+Es/v9M7gHa8U2IdJkX9/jdgoplN93m8b+ON2H88kmEzItsNwDn3lHPuRLxC\nbHWk/TjntjrnvuycGw9cgndabZ8E34ufPI71+UsAVDRlCefcOuD3eFd+dCjFC4odQIGZXQ2U9XKY\nv+D1Yq7BO58ejmx/HNjPzC4ys8LIzxFmdoCftkWKsAOBjiHqUqAWqI/0wLoUX865Cry5WHcDf3TO\nNUUeWg7UmdkC89YxyTezg8zsiMjrXGhmoyPtrok8J4yIBC4yGfnbHROgzWwS3gj1i8A2vCKkKOop\npcAHzrlmMzsS75Rch3uBz5jZuWZWYN6k7UO7veTXgDXAY2ZWnEhbIxekPAT8ODJKtD/e/KqOx9cC\nNwP3mzehvMjMhprZeWbWYwQ/8l6agBoz2wOv09rxuYwxszMjxV0L3inCcOSxc2z3hPFqvOIm0Ywa\nUB7LwKhoyi7XANG9sKfwemfvABuAZnoZto3MX3qIyMTrqO11eKNE5wFbgK14IzlDemnLTZErP+rx\nip8fOOeeiDw2Hy8w6/B6YL+P8fy7gIOJWqogEnyn400SfR+oAm7FO+UIcArwZuQ1bwTOiyq4RCRY\ndcDHgZciV2m9CLyBNwrzLF4naauZVUX2vwy4xszq8OZhdl6o4ZzbCMyMPPcDvInTh0S/WGTi9zyg\nAngkzgUtvfkaXlZsxcuV++m6PMI38CZz/xav0/UucBbexSfd/QrvdGFV5H0/GfVYHnAFXlZ+gDfX\nqaNjeATe51WPN+r2Tbd7bSZf+pnHEhCLfQGCSGqZ2Qy803RT4lwlIyLSb2b2C2Csc+7iPncWidBI\nk6QdMyvEW2TuVhVMIhKEyOnEj5rnSLwLRx5Odbsks6hokrQSOS9fgzeBMuZVOCIi/VCKN/2gAW9K\nwC+BR1LaIsk4Oj0nIiIi4oNGmkRERER8UNEkIiIi4kNBMg76fM3zOucnkkNmjJwRb8HUjKP8Esk9\nfjNMI00iIiIiPqhoEhEREfFBRZOIiIiIDyqaRERERHxIykRwEemHMBS2FpIfzsdIv3nVDkcoL0Rb\nUZu6WyLSVZrnFwSTYSqaRNJEYWshw4qGYYWGWfqFjnMO1+ZoaG2gbWhbqpsjImkk3fMLgskw9RdF\n0kR+OD+tA8fMsEIjP5yf6qaISJpJ9/yCYDJMRZNImjDSO3AgEjppOvQuIqmTCfkFA88wFU0i0umf\nT/+TWYfNYuYhM7n1l7emujkiIglJdoapaBIRAEKhENd9+zpufuhmHnn5EZ5Y+gTvrn431c0SEfFl\nMDJMRZOIALBqxSomf2gyk/aeRGFRIaeefSrPPf5cqpslIuLLYGSYrp4TyUBfnnEejVUf9NheMmoP\nfvf8A/065vbK7YydMLbz7zETxvD6itf73UYRkViSkV8wOBmmokkkAzVWfcCLo8p7bP9EjCASEUkn\nmZxfOj0nIgDsNW4vtm7e2vn3ts3bGDNuTApbJCLi32BkmIomEQHgoI8dxIZ3N1CxvoK21jae+OMT\nHH/a8aluloiIL4ORYTo9JyL/v707j4+qvvc//vpOkiEJJBDZEhIMWihq69pIrV6prVUUhWKL1l4r\nttVCpe3Parlir621vXa9XK2trYWKihu2ULFob6FY5NrWBVFR3AIIypYQggnZk8nM9/dHFrPMJOck\nZzLb+/l45AEcTs58JzJvP+d7Pud7AEhPT+c/l/wnX5/zdYKhIJdceQmTj58c62GJiDgyFBmmoklE\nOk2fMZ3pM6bHehgiIgMS7Qzrt2gyxkwF/tBl07HALdbaX0ZtVCLSp+wxR4Vtmswec1QMRhO/lF8i\n8SeR86vfoslaWwqcAmCMSQP2A2uiPC4R6cNgbstNJcovkfiTyPnlthH8XOAda+170RiMiEgUKb9E\nZFDcFk2XAyujMRARkShTfonIoDgumowxfmA2sCrC3883xmwxxmxZe/9ar8YnfXj+qedZNG8RV5xz\nBYvmLeL5p56P9ZBE4pLyKz4pwyTRuLl77kLgZWvtwXB/aa1dBiwDeKb6GevB2KQPzz/1PEvvXkrR\n/CJOmXoKNaU1LL17KQBnfOaMGI9OJO4ov+KMMkwSkZvLc19EU9txY/UDqymaX8Soj4zCl+5j1EdG\nUTS/iNUPrI710CSBff/a7/PJYz7JJdMuifVQvKb8ijPKMPHaUOSXo6LJGDMcOA94LGojEVfK9pSR\nOzW327bcqbmU7ymP8B0i/fvsFZ/l7jV3x3oYnlJ+xSdlmHhtKPLLUdFkra231o621h6J6mjEsYKj\nC6gprem2raa0hvyj8yN8h0j/Sv6thJF5I2M9DE8pv+KTMky8NhT5pWfPJai58+ayb9k+qt+oJtQa\novqNavYt28fceXMjfk+qNF2myvsEqKqsYuHnb6D6cHWshyLiitsMS5XPdaq8T0jM/NJjVBJUR6Pk\n6gdWs3vPbvKPzmfBtQsiNlCmStNlqrzPDqvvf4JtW5pYdd9avrZoXqyHI+KYmwxLlc91qrzPDomY\nXyqaEtgZnznD8Qepa9Ml0Pbr/LbtkUJq9QOrKdtTRsHRBcydNzchPrRu32ciq6qsYu0j/2L0+N+y\n9pGFXPqV2YwaPSrWwxJxzGmGDeRznYgZpvyK//zS5bkU4abpsuNsJ+uKLE65/xSyrshi6d1LE2Ka\nOJWaS1ff/wStrbMYlvlhWltnseo+rS8kycnt5zpRM0z5Ff9UNKUIN02XiXwrcKo0l3acpWWPuAKA\n7BFXsPaRfw26N+DGr9zIl879Eu/ueJdzp57LYyt0w5nEntvPdaJmmPIr/vNLRVOKcNN0mchnOwNp\nkE9EHWdp6eljAEhPH+PJ2dov7vsFT+98mleqXuHvpX/nc1d9zovhigyK2891omaY8iv+80s9TSnC\nTdNlx9lOx3V1SJyzHbcN8onq+ae3EGw9TFXlyh7bRydMQ6WIU24/14maYcqv+M8vFU0pxGnT5dx5\nc9vu2JjfdnZWU1rDvmX7WHDtgiEYpXcsyfs0jOV/+VWshyAypNzc+JIMGab8ik8qmqSXRD7bSbVb\ndkWkt0TNMOVX/DPWel/N6oGXEiuL5i0i64qsbtPy1W9U0/hwI0seWBLDkfUvqyGLrNysWA+jX401\njTRmN3bbNn3UdBOj4XhO+SWxovwaGoPJMM00SUKuZxJJ2Z4yTpl6SrdtuVNz2b1nd4xGJCLRpPyS\noaS751Jcoq5nEkmq3LIrIsovGXoqmlJcoq5nEkmq3LIbLeX7yvnqzK/y2ZLPMuf0OTz024diPSSR\niJRf0tVQ5Jcuz6W4ZJsOTtQG0HiRlp7Gop8s4oRTTqC+tp4vnP0FPvHpT/Ch4z4U66GJ9KL8kq6G\nIr9UNKW4RF3PpC9ubk2W7sbmj2Vs/lgAhucM55ipx3DwwEEVTRKXlF/S1VDkl4qmFBKuYTLSeibn\nfOIcFs1bFBfNlcnU6Omlf2z4Bw/e/yAH3jvAhOIJXPnlKzn7vLM9O/7+9/bz9mtvc1LJSZ4dU2Sg\n3OTXgmsXxE1uxMs44k2i5lfarbfe6ukBAd5res/7g8qgdDRMjv7KaIqvKSY0IcTTS5+m5PQSSk4v\n4bWHXuOdFe+QuSeTj5d8nE3Pbeq1b/7ofIqOLYqLccdiLNGWEcggY1iGo33/seEf3P6b2xn95dFM\n+tokggVB1v9uPYWjCyn+UPGgx9JQ18C1n7+W6265juNOPq7b37U2t9Ka0dptW3Fm8Q8H/aJxQvkV\nf9zk17xr2laUjofcUH6FF8v8gsFlmKN1mowxo4B7gI8CFviqtfa5SPtrnZP442b9j4GsFRLpbGqw\nZ1mJvG6JW27WOZl/xXwy/z2TvI/mdW6rer2KpkeaWPbwskGNIxAI8M1Lv8mZ557JVd+6qtffJ9o6\nTcqvxOc2B9zur/wavETJLxiadZruBNZZa+caY/xAtsPvkzjhpmHSbXNlpFVsS7eWsum5TYNa3TbZ\nGj29cuC9A5x63Kndto08biS73ts1qONaa/nBN37AsVOPjRg4CUj5leDc5oCb/ZVfQy+R86vfJQeM\nMSOB6cDy9kG1WGurozIaiRo363+4XSsk0m2/ax5dM+jbgbVuSXgTiidw5O0j3bYdefsIE4onDOq4\nrzz3Ck+sfIIX/u8F5p45l7lnzuWZ9c8M6pixpPxKDm5zwM3+yq+hl8j55WSdpmOAQ8B9xphXjDH3\nGGOG99zJGDPfGLPFGLNl7f1rPR2kDJ6b9T/mzpvLzjt3UrqhlF1v7aJ0Qyk779wZca2Qsj1lNFU2\n8cJ3XmDT5Zt44Tsv0FTZRENtA7lTc7vtmzs1l/I95VEZdyq58stXsvf3e6l6vYpQa4iq16vY+/u9\nXPnlKwd13NPOPI1ttdt47PnHWP3salY/u5rpM6Z7NOqYUH4lAbc54CbDlF9DL5Hzy8nluXTgNOBb\n1toXjDF3AjcB3++6k7V2GbAM1BMQj9yu/xFqDFG5upKWIy34R/rJaIzc4JeVlcX2h7dT+I1Chn94\nOPXb69n+m+1kpGUM+nZgrVsSXsddJg/e/yC73tvFhOIJ3PCNGzy9+yRJKL+SwEBywGmGKb+GXiLn\nV7+N4MaYfOB5a+2k9j+fDdxkrb0o0vcodLw11LesLpq3iIrsCio2V9Ba30r68HTGTRvHuIZxYZsX\nv3bx1whdEmLUJ0aRlplGsClI9XPVND3YhH+0n6L5Rb1uB0710AgnUR54mUiN4Mqv+BDPGab88kai\n5BdEuRHcWltujNlrjJlqrS0FzgXeHNBIxbVITYrgvBnRrdItpbTmtTLx5okM/+hw6l+vZ9/t+6iq\nqgq7f0NdA1OmTeHI+0dobmkmw5/BxGkT2fngThZcu0BnWRIzyq/Yi/cMU36JG07vnvsW8HD7nSe7\ngK9Eb0jSVdcmRaDt1/lt26P14W2xLRx9/dHknJoDQM6pORRdX8Se7+8Ju3/B0QUEDwQp+sgH645U\nv1FN/tH5Wt3WBYvFWosxcTlpA7TdnWJJuIkY5VcMxXuGKb+8kQj5BYPPMEdFk7V2K1Ay4FeRAYvF\nLauhYIisqVnYkMX4DDZkyZqaRSgYCrv/3HlzufP2O8m5NIeMogwC+wLUrqrluhuuY8WSFax5dA0N\ntQ1k52RzyeWXcNWipLmV3VNBXxAbsJBBXAaPtRYbsAR9wVgPxRXlV2zFe4Ypv7wR7/kF3mSYHqMS\n52LxbKXhucNpKm1i+EeHE7RBfMbX9ufcXjcddQrXdPn3P/2dZ7c9y8TvTiTnxBxqt9Xyxzv+CKDg\nCSPgD1DfUk9aUxqG+AsdS1vYBPyBWA9FEkgiZJjya/DiPb/AmwxztCK4W2qk9E7XfoCezYiAq+bK\nSGdNPZs084bntYXF9R+Exd479nLZnMuYesrUXq+5+oHVYVe93fztzRxz2zHknvbBbbs1L9dQ/tNy\nbvrZTXoeUxKJ10bwgVB+ecurDHOaX3PnzaV0ayl/fPyPjjKs+lA1Bd8uUH6lOK9XBJcYiXTLKuCq\nuXLFkhVtIdLjrGnfO/vYWbGz23F2LtvJmSeeyYs/fZFdtbvIzsnmssvbwibca9a8W8MZU7u/Zu7U\nXFoDreScmNNte86JObxz5J0hbwwVkdjwIsPc5NfSu5ey4NoFXMZlrPnpmn4z7K1b3yKvMq/b6ym/\nJBLNNCUot880mlMyh/zv5vc6a9r9vd1M++W0QT2TbtvN2zjxxyc6PlNz85qSGDTTJG65yTAv8ivS\na5ZuKKVydSVnLT2r2zGUX6nFaYY5WRFc4lDZnjJXq9U21DaEPWtqDbSGPU7pllLmlMzh/KnnM6dk\nDiuWrKBsTxlpE9LY9+4+dm/fzb5395E2IY30tPSwq95OP2c6e+/YS83LNdiApeblGvbesZdh6cMG\nvdKuiCQ2NxnmNr/K95SzYskKRxk2+iOjqd9dr/wSR3R5LkG5ba7Mzsmmdlttt7Om2m21pGek9zrO\ntp9to3VkK4WLCrtNhWcFsti7eS+jPjGK7Mxsgk1B9j63l7yxeVx97dVh1zNZsWRFrynyba9tG/LG\nUBGJL24yzE1+1ZTWEGwJhr2cFy7DKp6rYMy4MTQ+3Kj8kn7p8lyC6qu5ss+eph6NkWeeeGZnT0DH\ncZ6/7nmOue0YRn2sSyi8XMPOG3eSNSmLsf8+Fv9EPy17Wzj0yCHG+8dzz1/vcTX2O358B4HswAd3\nqzRkcP3N16snIEHp8py45SbD3OTXvmX7OLTzEEW3FPW6tOZFhim/kpMawZOc22caddwi2/Osqevd\nJx3HIQQjTxrZ7ftzTswh2BokFAhx6E+HaD3SSvrIdEKBEFXV4VcK74svy8eYuWO6rYsiIqnDTYa5\nya8F1y7glm/cEvZynlcZpvxKXZppkl4iNV3u/O5OJv90cthbcB/f8rjj47ttYpf4p5kmiSfRzDDl\nV3KK6UzT5hfd7T/t9GiMInUN9uGYl1x+CX+8o/dUeKY/k/S8dIKNwc4HW6bnpZOelu7qNWOxQrCI\nJAYvHu7rNsNs0LJo3iLll/QrKkXT1Kbprvbf/OIzjvdVgdU3Lx6OGWkqfNtr26Aagv5g54MtM6sz\nyRub5+o1Y7FCsIjEP68e7usmw0y5oZVWsq7IUn5Jv+Kip8lpkVWa+YzjWaxULa6i+XDMufPm9m7c\nfHgfacE0V6/ZcRzmE3aFYBFJTdF+uG+4DHv17leZ9MVJyi9xJC6KJqfczGA5nb1KtuLKi6njSKvv\nXsZlLLh2Qa+my1/f9uuw65ZEek23Tewikhq8uvTlJsMyGjKYdNkkx6+p/EptCVU0ueGkwHI6c5VI\nhZUXU8drHl3DxO9O7GyWzD0tl4nXT2TNT9fw+KLHe4XD6gdWu37NMz5zhkJGRLrx6tKXmwxbNG+R\n8kscS9qiyQmvCqt4KqrmzpvLz2/5OYHsAK01raTnppPRkMHiHy2O+MDLnhpqGwjWB9l+43Zaylrw\nF/gZO2ssDbUNYZs0586by52330nOpTndbsG97obrYvATEJFE5UV+gbsMO/GkE1l35zrllziS0kWT\nE/0VVvFWVJVuLaWZZsZ9YTzDJvpp3ttCxX0HefSuR9lRuaPXdDXQK3gy0jIoe6SMwm8Wkv3hbBq2\nN7D/rv348IVt0jznE+cQagxRubryg8XeGjOG7k2LSFLwIr/AXYatu3MdjRWNNK9uVn5Jvxyt02SM\neReoBYJAq7W2pK/9n3gCrXPS7s+v/4J/rl/N+wfLOGp8Af82Yy7HlXwwreukoHJzhjWnZA7jvzue\nzOOzMcaPtS00vdXAO999x/H6JFeccwUZX8wg96xcfMN8hJpD1PyrhoO/OkjJ7SWOH9irdUtSRzyv\n0+Q2v7RO0we8uP0fnGeYF/kF7jIs0gN7lV+pJRrrNH3KWls5wPGkpJde/it//9sKCq85mmOnTKZm\nRxV/v2cFRS0n8rHTLux3lmra6ZEbGiH8GVZDbQPZxw0nhA8wQBrZxw3HBm3YFXJ31e4K+9oFpxZQ\nvb+akA3hMz4KTi3gQOuBsA3fDbUNrhrBRWJA+eWSV7f/u8kwr/ILnGdYRlEGLUdaum1TfkkkujwX\nRWv/fgeF1xzNqONHA7T9eg2sve8OPnbahX1e+usoqFY9tIbC701kxCm5WGDEKbkUfnsia362JmzR\nlDUii5ptNeScPAYAY9Kpea0Sk2bCPvAyOye71zEKji7AVBrSMrJIN0dj7R5MpSE7Jztsw2Sk7Vq3\nRCRxeXX7f19N2T0zbKD51fPkc/ioApr3GXwjsvCZo4E9NO8z+LN6Z1VgXwD/SH+374+n/HK7WLQM\nzPTznO3ntGiywFPGmCCw1Fq7rOcOxpj5wHyAhQuXcsEF8x0eOnkdrNjNyVO6X3/LnZLH7oot/X5v\nR0HV0tBI7kdGYqyhNdBCeoafnI/msLtmV9gP04eO/jBv3vE6+VeHGFbsp/m9FsqXlzFmxDj2/M8e\nxn91PMOOHkbznmYO3nuQL1z+hV7HmDtvLj/7r58z8gujySzeSdN7Tez7w24uufwSNi3bRPDqII1Z\nTWQ1ZlK2vKxzu9YtkTjlKr++c8d3mP3l2UM8xPjj1e3/DbUNbbNEFgItATL8GRFniQaSXx052PUk\n9PJP/ZBf3X4VI784isxJ79D0biP7V+5h1tnf5v9+vYL8rwYJ5DaRUZPJ+4/UQmMG5S9VM+5k7/PL\ni6LH7YLREj1Oi6Z/s9buN8aMAzYYY9621nZbCKk9iJaBepo6jB93DDU7qjpnmgBqdlQxftwkx8fI\nys6h9o0ahp84nJC1BIOt1L9eT3Z2bq8PUmnmMxzYW0+wMcShRw8SrAuSNiKNYF2IZpvOsMxhHPrD\noc67UoYxjKmnTO31mg21DTS+30Trn6pprWshfYSfwPtNTPzQRBacsoC7bvst5XsryZ84hm9+byFn\nfOYMpj41VeuWSLxylV/qaWrj9vb/SMWBPyubI6/VtmVYCAKBIPXb6vFnZbP5xe59ndWV9YTqu+dX\nqD4EGW15FS6/pp3e9tqlmR/8J90ZeIGGI/UEHoNgXQVpI/wEjtRTOGEq10y+i3t+cT0Vh/Yzbmwh\nC794DwBrl9/BC4de5ajx+XxqxgJ8I8/wbJZnMEVP1/clseeoaLLW7m//tcIYswaYBui/ZD9mn3s9\nK+5ZBNe0zTDV7Khi/z17uOp8582FM8/+JmtvX0L+/ytg+Al5HHmtivJflTH77EW99p3aNJ38CRM4\n9isTuxVq1W8d5rUfvkDBzELef+UQwdpahuVmc9Qnx4adar/3zvvJ+8wEGnY2YOpa8GVnkPeZCdx7\n5/3c9adfQX0+ReMeo7V+IcefdjzQ1uNw3KnH8ZNr7+DmX97AyKNGDvCnJuIt5dfADGTl63DFwayz\nv90tw2q6ZNjUpulsfvGZzsLpqGOyKfzetLA3mxTOKeTQlkPU1taSnZfN2PM+yK+eN9T86j/u56j2\nDAvVtZCWncGIz0zgkT//gJ9//59QN4GCEX8mWHctUyZPIzd3NFMmn84ddyzg+q8tIzd3NDR58mMc\nNM0yxZd+iyZjzHDAZ62tbf/9+cCPoj6yJPCx0y4E2nqYdldsYfy4SVx1/pLO7U5cftktvP7Gc7x9\ny7+woT0YXwbHFZ3F5ZfdEnb/SJcEm6rrqHyhnHFXj2PYsRNo3tVMxfJyDr7X+wyx/L1yMrOGUXBN\nAVlTxtG4o5Gye8po2dvMkys2EGydRfaIKTRXz+KJ+//Gl264FIAnV2zgrZdau20TiSXl18B5tfK1\nmwyLdEmw7nAdB/51gPFfHU/+MRNo2d3EgXsP4NvnC/uaFXvL8YfJsOaDAdavf4Bg8GKysqZSV3cx\n69ev4NJLb2D9+gfYvr2q888i4TiZaRoPrDHGdOz/iLV2XVRHlUQ+dtqFroqknmpqKjlc0UzhiF2k\npY0hGKzkcMVl1NQcbjsb6iHSJUFfZjrjrhpH5oczAT+ZHzaMu2oc5bcd6nUmkzkymwlX55N7SlvT\npf+UYZirfRz4rzLWrXyRrBGPApA14grWrbycWV8+H2st61a+yOhxv2XdyoXM+vL5mm2SeKD8GoTB\nrnxdmvkM9UeqKTtUxeic10hLG00weJiyQ5eHzbCulwQbGtq21bxVg29YGuPmjWPYlCyM8TNsimHc\nvHHs/6+DnSd9XWebsvOyyb8mv7NxPPO0DzJs48Ynycpqu3svK2seGzdexplnXszGjU+Sl3c3Gzde\ny4wZV4XNV5HwZXoX1tpd1tqT278+Yq398VAMTNp0nBWlpbXdTdJWOLWdHYUz+9zr2X/PHqrfOkyo\nNUT1W4fZf88eMjOG4xvpI9QM1kKoGXwjfaT72u4aqamp5Ic//Dw1NYcZ5svGn+cn1GgxIR+hRos/\nz08wEKS+fhYNDfDe9i/R0AD19W2zTU+u2ECg+SIq9g8n0HIRT9z/t84xVR+u5sbLfsCR949E/wcm\n0oXyK/b2v7aBjPRZ5OaOZvhwyM0dTTA4K2yGzZ03l3d+vY/yl6oJtYZofKOFimWV+P2ZpOWmteVX\nqC2/0nLTSPOlM7VpOvVHqlkw44OMSU9LJz0vnWBjECwEG4P4j0qHUJDG0Lk0mTr2HfgsYAgGL2bp\n0sUEAhdSWZlGIHBht7F1zUYRLTkQ57Zu3UQweIAjRx7psX1C2CnkSJcEH1v/C+q3lzEsOAxrGzAm\ng+Z3AhTkTwHoNjU9segEfBWNhNKaaWltID3dj78ihwxfNmktazhSvpzmxlEcKf80/hHZbFiTQ321\npbH+dzTWW0z6LNat/HrnbJMu20ki0S3e3tqy6VWCrU9TXbmyc1soCFu3Htstwza/CL6RZ3DB2Gz6\nJAAAHbFJREFURfDy8qd4u6K0M78e3nAzDdvryAxmduZX0zstjJlQBMA7a3ey5+1Wfnvb3zj3i5cy\naeokqIagP0hzSzO+tAxMRSYWP6HgSqoOLqW5cQwHD55OVlYub77ZSHb2bTQ1BfH7Z7Jx47c6Z5t0\n2U66crQiuFu6ey7+/PLO+byw538Zc+VUMo8eQ9OeSiofLOXjR8/kq1/5Cf/xH5+nqupm8vJ+zJeu\nXMiqf/6ICV8tpDG3hqyaXA7cu5+rzl/ClMmns3jxZaSl3U0weC0///kq1q9fwfr1QaqqZmNMMda+\nx4ij/sjHZ1Zwxszz+M31P8GX9lv8GQv5zfqbddkuCcXziuBuKb8GJtJdXuGeehCuMO2r4dlNfv33\nfz/G03uWs+4vS8n/akHn0gKHl1eFzbCzzvoUmzZldsuvvLy1zJiRxowZ83rlnS7bJadZs/B8RXBJ\nYIcqymnda9l/+2YsQQxppDXlciiznPXrH6C29pO0tBRTW/tJysvaCqR7/vuD23Kv+WLbgpyrVt3e\nq4ly69ZN1Ne/TTD4e3y+XEKhGlrqYP+W43indSdprZeRnjWF+rpZnWeCHeLpYcciMjhOP89d93My\ns+cmv9pmhG6kqOXEbksLRMqw//u/B6ivb+iWX/X1sHXrcQBhm8YldfXb0yTJYfHiezkqbzLUbSCt\n4X2o28BReZNZuHAJTz31Z5qaZpKeXkxT00yeeurP5I//UPttuVugbgJTJk+jpqayvYlyHtDRRPkk\nCxcuYdSoIoqLn2XSpC0UFz/LqFFFLFy4pHP/TJvDyMwFbPvbGxRUfKTzrHLzi92/RCS1dBRQfa1H\n5Da/amoOM2Xy6Y4yzOcbSU7O+D7zq2PfjRufVG9Tiku79dZbPT/o9u14f9AEVlNTyc9+diWnnfYZ\nhg3r/diS/rz08l9Z+tA3+MPjP+LFV58kN2sMEwqmuDrG2rW/49VX82ltPZdg8DDGjCEUqmT37ocp\nL59GIHAaweC3MOZCQqE6du9+mKqqT3Lw4LH4/SGMeZ133nmVnTs/TGbmuQD4fNk0Nx+mtHQ5tbXn\nkZFxMuXlVzJixGxaWho7t/fc39pX+chHPoH//eHcc9v3OO+kqylMO57D6e+x/wC9vgoLXf/IZIgV\nZxb/MNZj8Iryqzun+XU4/b2In9Xnn3qeX976S1bcuYLnNj5Hbk4uRccWdf59YWHbZ31Ma3HY73eb\nXxkZpbzzzqu8/fakfjPs/fd309JSx/Dhs13l12BzXeLL1Kk4yjD1NA2BVatu5/HHn2TOnItdT+2+\n9PJfWfG3RRRec3SvBTLdLGVw000XUlr6OtZmEgo14fNlYkwTfj+0tEAolI61eRhThTHNpKePwOd7\niKamEWRm1jF69E3k5vqprOz9zNOGhkqys8dQX/8+jY2jyMqqZvjwozq395SfP4Ef/3ito59LuLNP\nXdKLP+ppSl5O86s085mwn82uD/7tuUhm1+UMwj0OpYOb/PL5WvnQhz5Mfb3l8OGf9Zth1dUVQICM\njCzP80sSh3qa4kTHdHC49T9qairbVqC9flnE5sL+Hvrr5BgAH/vYeVRWfoKqqk2kpd0NXEte3qeY\nMOFlDhw4laqqTUDbdr8/G2tPoqEhCyikqWkPzc3nU1Li59JLbwj7mjU1lSxefBljxjhrmOzr59JV\nuADd/KIKKZGh4Da/ej4WBfp+8K9v5BnUH6nm0f++g+/9v9URM8NNfuXlfYrs7Jd5//2P09TkLMOi\nlV+SfNTTFGUd6yz5/VN7ra/U9VbWSA5W7CZ3Sl63bblT8jhY8a7jY0Db0gV1dfcTDJ6MtUGCwZOp\nq7uPHTte6bW9sfEFGhvvA+YA04E5HDlyN1u3bor4mn29T7c/l/5MbZre7QvUGyUSDW7yq+tnsauy\nPWXkTs3tti19Yi7v7igH2pYL2P+W6TMD3ORXx/YjR+7GaYYNZX5JYlPRFEWRGqdrag73OFOJ3FzY\nscJ3t+O2P/TX6TGgrZEyL28SxcU3M2nSCRQX30xe3iSWLPlbr+1jx07B58sGHsKYF4CHCIUyWLjw\nf8K+Zl/v0+3PZSBURIl4byD5Fa5w6ljlG6Choe2rbkcNRWOPo6DiBEcZ5ia/8vImceutjxIKZeAk\nw/bv3x7T/JLEokbwKFq79ndhG6etfbWzITEra1a35sKecrPG8I9Vq/Af7cefl8mR0vfZf88evnDe\nD9jy4t8dHaOvsXQ0O/p8J/Dee5eSk/NZKivX0dp6FnAxxowCMoAq9u37A7W11b1eM1KDeKTx9PVz\niTR+N8a0Fnf7CtdgruZyb6kRPPkMNL+6fuYKCyE3J5d1v3oaX4GfjDw/TW8FKP99masMc5Nfra3N\nPPfcT6iruwiY2W+G9dfw7ebn4kV+SWyoETwO3HzzbMrLD/TaPmbMaGpqAvj9f+x8nlxLy2URr6O/\n9PJfWfv3OzhY8S7jx01i9rnXdy7Q5vQYkcbS0exYXV1GIDCWjIxDBAJNtLW7jaNtMjIEVJKVlc5R\nR03p9ZqRGsQ7GiadjiXS/l5Tc7n31AiefLzIr47PWt2z9YPKMDf5NWpUAYcP7yYU8gNj6C/D9u8/\ni5ycLHy+7i2+8ZpfEh1OG8FVNMXAqlW3s2EDjBjxwR0XdXW3c955OL4Lo79jOG0QB9i/v5RvfvMi\ngsG7SEv7JhdddCmbN4/F7/8i+/Z9haKiFbS0PEx+/j8oLz97UOOOVz0LKRVR7qhoSh1e5Fd/x5kx\nY96A8+uuu/7Ks88+wYYNpFSGyeDo7rk45vZ5cgM5hpvnJS1dehOh0CXAMYRCl7Bx40qyssZQVvY/\nhEJjKSs7jVGjCtixo5Ls7L2DGne86nqXXmnmM916MlRAiXzAi/zq7zjAgPNr6dIbCQaDBIMHUirD\nZGhopikJddw+6+R5SR+cpT2IMadi7SukpV3J97//G2677RsY8xjWfo5f//qvFBa6W1AzGehSnjOa\naRKveJFfd931VyDEt751UcpnmDjjdKZJd88lofXrHyAQuJDKyjQCgQu73Q5bU1PJD3/4+c47Pbqe\npUEmHWdrS5Z8nVDocoLBbEKhy1m69MaYvJdY6+/OPBHxlhf5tXTpje1/pwwTb6loSjIdt8O2tMyk\nqSlIS8vMbrfD9lyfZPv2l7D2IeA8rD25/deHqKurAS4nFAoCl/P669vYv39HrN5W3NDSBiLR41V+\nvf32i7z++jaUYeI1x0WTMSbNGPOKMebJaA4oGfU8O+pv+2CO0XGWVl+fTnp6MfX16Z1nazU1lTz1\n1J8JBG7qfKjl5z//bfLz/4PJk7cxefKrTJ68Db//S8DpWJuBMcVYm6EztTA0C5U4lF8D50V+OT2O\nF/mVn/8fjBo1llDocmWYeM5NI/h1wFtAbn87SneRmrLdNGs7PcbWrZuor3+bYPD3+Hy5hEI11NfD\n1q3HAVBb+0laWoqprf0k69evCNuMGQjsB5qxdiYwAqgDGtixY5iHP5Xk01czOagXKsaUXwPkRX45\nPY4X+QVw+PBerF2OtStRhomXHM00GWOKgIuAe6I7nOQTaeVcN6t5uznG4sX3MmpUEcXFzzJp0haK\ni59l1KgiFi5cwlNP/ZmmppmkpxfT1DSTp576M4sX38fy5Vu6fT344DYKC0/hmGNeYPLkVznmmBeY\nMOF4li59aUh+ZslAs1DxQ/k1cF7kl5vjLFy4ZND5tXz5Fh544G0mTDheGSaec3p57pfAjbStEBaW\nMWa+MWaLMWbLunXLPBlcMoj0jCI3zy6K1BgZ7hgd24LBALt2XdB+6+3FLF26mNraTwKTMCYTmNR5\nthZpzGlpbU/4blsETs9XGgwVUDGl/BogL/KrY38nGbZ06eJB51fX4yrDxGv9Fk3GmIuBCmttnyW6\ntXaZtbbEWltywQXzPRtgIov0jCI3zzqK1BgZ6RhbtvyNYPARyspKCIXKKSs7jWDwEbZvf4nGxvuw\ndibBYAnWzqSx8T5eemlDr9dsm/J+hCNHSjq/gsFHOh92KYPTcxZKBVT0KL8Gzov86nocJxn25ptv\nEgg8MKj8AmWYRI+TnqazgNnGmJm03dOZa4x5yFr7pegOLfFFOtvpOJsKdxbUczXv3o2R7+H3Xxjx\nGCUlcOaZF/Gtb11ERsYDWPs5fvSjlZ0r5PZcCfdjH+s9bj0KYGh1zD5pUc2oUH4NkBf5lZs72lWG\nHXXUAj7+8UP85S+rBpxfoAyT6HG1uKUx5hxgkbX24r720+Jwbfp7XlJPHc8uWrXqdh5//EnmzLmY\nrVs3sWvX2zQ20tkYmZUF0BLxGGlpabz22olkZPyIQOAWTjppG8FgUM9LSiCJ9liXRFjcUvnljhf5\ndemlN3DzzbNdZVhj42EaGq5UfsmQisqz5xQ60ddzNdzvfe933Hbb1x0/mHf//tL2VXD/gc9XQChU\nhrVnazXcBJYIBZSKJoHwq3mDdfxgXuWXxEpUVgS31m7qL3BkcNqmss+hsvI/CQQ+1edUeDhtq+D+\nOz5fAUB78Py71idJYJGayMUd5Vf09cyvrjenOMkw5ZfEOz2wN450NEwGAp+iqamKYcPgzTffJCdn\nt+MHTO7Y8QqwmUBgeY/tGdEcugyRrmtBbX4x/megJHWEy6+NG58kN9dPMFjpKMOUXxLvVDTFkY6z\ntLq6p0lLu5u6umvJy/sSM2YMd/wE7pUr3x3Qa/ds3pT4F2kxTRVPEgvh8isj41OUlCi/JHno2XNx\nZOvWTdTV3U8weDLWBgkGT6au7r4huU225zOdJLHo8p3EmvJLUoGKpjiyePG95OVNorj4ZiZNOoHi\n4pvJy5vE4sX3RfV13a7uK/FL6z9JrCi/JBWoaBoAtw+qdGogq9h6MRa3q/tKYtAK5BJJNDJsoKtw\nD3Ysyi8ZSiqaBiBaU8EDWcV2sGOJtOqvztaSh+6+k56ikWEDXYV7MGNRfslQUyO4S92ngq9lxoyr\nPGs8dLtImxdj6evs0GnzpiSOSHffqXk8dUQrwwayyORgx6L8kqGmmSaX4mkq2Iux6BlNqUuzT6kp\nmTJM+SVDzdWK4E4l64q6HavdOl2dO1XGIsmh68rjbmeeEmFFcKeSNb8gvnIjnsYiCWbz5v73mTbN\n1SGdrgiuy3MueD0VHGltESdrjmhaWrymS3fJz8vcGEx+eT0WSUBOCp8+zJp2MOLfPbF5/AfHd1k8\n9UdFkwttU8EHHK/O3Z+uDZBdvz/S9miORaSrjgJKi2YmFy9zYzD55fVYJEaiWPh4cdxoFE+6PBcj\n4R5smZs7OuJ2kVjquHQXqXDS5bnUovxKIf0URtEqfLz2xObxbb+JUDxF5YG94p1IDZDx1KQp0kEN\n49KV8itJbd7c+4u2wijSV6LoHGuX9zUQujwXAx+sLfJHoGNtkcs488yLw273clkDkYFSz5OA8iup\nhCkeEqkQcsuLy3YqmmIgUgPk0qWL1RgpCaFnz9P082I8IBkyyq8E1qNISuYCqS9hi6dZzoonFU0x\nEKkBcseOSrKz96oxUhJG19knSQ3KrwSSYjNJbg3kZ9FvI7gxJhN4BhhGW5G12lr7g76+R42UIqnF\naRPlUFN+ScpQgTQ4s2Z5tk5TM/Bpa22dMSYD+Kcx5q/W2ucHNUBxxenaJyLSjfIrTijDPBShkVlF\nUvT1WzTZtqmouvY/ZrR/6UxsiDld+0REPqD8ih/KsEHQLFLccNTTZIxJA14CJgO/sda+ENVRSTfR\nfEiwSLJTfsWeMswlNWzHLUfrNFlrg9baU4AiYJox5qM99zHGzDfGbDHGbFm3bpnX40xpWvtEZOCU\nX7GnDOtHP2sjSfxwdfectbbaGPM0cAHweo+/WwYsAzVSeinSmig6UxNxR/kVG8qwHnSpLaH1WzQZ\nY8YCgfbAyQLOA34e9ZEJoIdaigyG8iv2UjbD+lh1WkVS4nIy01QArGjvC/ABf7TWPhndYUkHPdRS\nZFCUXzGW1BmWJM9lE+f0wF4RGbR4XadpIJRf0ic1aScnD9dpEhEJz+UjCEQSkgolaaeiSUQic/A0\ncP0PRJKSCiUJQ0WTSKpyUBCB/mchqUv/9qUnFU0iyUgFkYiI51Q0iSQSFUMi3nD4WRLpSkWTSDxw\nEeAqiEQGQItKigdUNIlEm2aHRGKny+dPnzEZLBVNIgOhmSGR+KZiSaJARZNIVyqGRBKTLr/JEFDR\nJMltAM2eClqRBKIZJRlCKpok8bgshBSkIklGC09KjKhoktjSTJCI9EdFksQJFU3inQGue6IAlITh\n9do+0/TMvk79/GyVExIPVDRJd4P8n4KCTRLeEP7P+4lULML6eM/KD4l3KpqSiUcBrOCSVDaU//69\nLcDGx89MmGaNJEmpaBpqUV66X2Ekkpq8/uwPtghTFkky6rdoMsZMBB4AxgMWWGatvbPPb9IzfSJS\nkIgMnQHllwDKKpFwnMw0tQLfsda+bIzJAV4yxmyw1r4Z6Rv0YROROOE6v0REIvH1t4O1tsxa+3L7\n72uBt4DCaA9MRGSwlF8i4iVXPU3GmEnAqcAL0RiMpIZP33ADNUeO9NqeO3IkG2+/PW6PLYlN+SVe\nUH6lNsdFkzFmBPAn4NvW2powfz8fmA+wdOFC5l9wgWeDlORSc+QIW0aO7LW9JExYxNOxJXEpv8Qr\nyq/U5qhoMsZk0BY4D1trHwu3j7V2GbAMgCeesF4NUERkMJRfIuKVfnuajDEGWA68Za3V/KCIJAzl\nl4h4qd+iCTgLuBL4tDFma/vXzCiPS0TEC8ovEfFMv5fnrLX/BMwQjEWSTKSmxn2HDvFmVVWv7V4s\nVHGwqirssfe1tlJy9dW9tqvBMrkpv2SglF8SjlYEl6iJ1NQ4+tAh5oXZP+DBawYg4rHVYCkiTim/\nJBwVTTLkMn0+tkya1Gu7FwFQlJcXNlwKd+0a9LFFRJRfqU1Fk/QSaVq6rKaGgtxcx9v3VVVBmABo\nDIU4eefObtvK23/tOQXtdvp5X1UVJWGmt5tCIcfHEJHE5ibDDlZVEaCtYOnKTX4B7KF3foG7DFN+\nxT8VTdJLpGnpwsOHXW8Pxw+8arq3mZRYy3Lg5B7HcXv2lhYKsSUjo9f2/NZWV8cRkcTlJsPerKpi\nHr0vf7nJL4B8awd9CU35Ff9UNIljDaEQE8KcYTW6PE4zUGi7L4UTBELAm+++2217pObK0Z/9LBm2\n93I6LcCbzc29trtZeMeLVXm1sq9I/ImUYU0ujhEuv6AtY3rmF4TPsHjPLy+Pk2xUNIljw4ADYbbn\nR9jf5/OFPcsaBuztse102ta/OCEtrdv2UCB8e2WGtZRHONs7Jsz+hvBnfLlhzgy9WJVXK/uKxJ9w\nGRYCJoTZ101+0X6MnvkF4TMs3vPLy+MkGxVNEjXj8/LYsnx5r+35s2c7WiBsoLKGDeu1LS0QCDsW\nEZFwlF8SjoqmFBduCnbXoUOcdOhQr31bIhyjBSgJMy29K8LaIi1EvqTX0GNqOkj45spY2FdVpbVS\nROJIpEtIbjLsM+2/9swwL/IL4ifDlF/eUNGU4sJNweYfOsRKeq8I+GnCh4UfeCDM9k8Tfm2R/EOH\n8PfYlgvMAIp6bG/p4xjhWKAkGOy1Pegb/LlhWiik6WqROBLpEtL4Q4d4NMz+4TLsCLAe6Nl+7Sa/\noC2rpvfYZgm/xpLyK3GpaIqBRG2ws0BWhO0Bl3d39Lzy33F+Vhbm2G4YCLuGysR339VZlogHEjW/\nIHyGVbT/6ibDencutemZX9DWM+WU8iv+qWiKgURosDue3g8mNIRv+jbAyWGaGglzdwi0BVdhj21B\n4GlgUo/t4Zoioa3Iyg9z/GbC/xzdrKibO3Jk2O0+F2d7kY4RrnFTJJEkQn4Z4IQI28Nl2BQgu2eG\nucgvaJup6n1fXvgMi/f86us4qZ5hKprElfK1a3tty58929UxDLC/R7NjYXMzkwg/kxXOh8aOddUY\n6aanINKZmxfHEJHY6plh+bNn9y6Y+hAuvwDym5t75VekWaZ4z6++jpPqVDSJJxojnJXFs9K9eykL\nBAa9CrmIJLZEzC9oW81cl+2GloqmFBduCrYFOCXMvn3dPXd2mO0Rp5qNobDH2iVB2qa9G8IcJ1pT\nxMFgkAKfr9e0d6TLDJquFokvkT6TLcBJYfYPl2Fe5FeHcPlFmON4lRkhF83dyi9vqGhKceHORiZ+\n7nNh7zyZEeEYfmBLpMcKOJyCLpwzh+wwjw+Ip/VJdOYmEl8ifSbdZJgX+QXxn2HKL2+oaIqBeK/4\nA8C8CNsj7X9ymOntSPuHlZER/uwtTAgNRLifeVkoxFSPji+SKuI9v8BdhnmSXxDVDIv0M/diKQJx\np9+iyRhzL3AxUGGt/Wj0h5T84r3iL8rLc3V3zDFjxw76bpr9q1Y5H+AAhPuZl1x9NRvjKOglOpRh\n3or3/AJ3GeZFfkF0M8yr5m4ZPCczTfcDdxF+/UKRqErkNWEkbtyPMkxiQPmVfPotmqy1zxhjJkV/\nKJKoojldH801YRLhMoMMnjJM+pKo+QXKsFhQT5MMWqKeMSXquEXEO4mcA4k89kTlWdFkjJkPzAdY\nunAh8y+4wKtDyxDT2YukGuVXclGGSbR4VjRZa5cBywB44onEXClMAJ29SOpRfiUXZZhEi+5XFBER\nEXHAyZIDK4FzgDHGmH3AD6y1sV+pS1KCptllsJRhEivKr+RjbDSeuaPpbZHUMmuW8yeexjvll0jq\ncZhhujwnIiIi4oCKJhEREREHVDSJiIiIOKCiSURERMQBFU0iIiIiDqhoEhEREXFARZOIiIiIAyqa\nRERERBxQ0SQiIiLigIomEREREQdUNImIiIg4oKJJRERExAEVTSIiIiIOqGgSERERcUBFk4iIiIgD\nKppEREREHHBUNBljLjDGlBpjdhpjbor2oEREvKL8EhGv9Fs0GWPSgN8AFwInAF80xpwQ7YGJiAyW\n8ktEvORkpmkasNNau8ta2wI8Cnw2usMSEfGE8ktEPOOkaCoE9nb58772bSIi8U75JSKeSffqQMaY\n+cD89j8+ZK290qtjxyNjzHxr7bJYjyPa9D6TS6q8T7dSLb8gdf4t6H0ml1i/TyczTfuBiV3+XNS+\nrRtr7TJrbYm1tgQ43qPxxbP5/e+SFPQ+k0uqvM8Oyq/IUuXfgt5nconp+3RSNL0ITDHGHGOM8QOX\nA2ujOywREU8ov0TEM/1enrPWthpjvgmsB9KAe621b0R9ZCIig6T8EhEvOeppstb+L/C/Lo6b9NdV\nSY33CHqfySZV3mcn5VdEep/JRe9zCBhrbSxfX0RERCQh6DEqIiIiIg54WjQZY+41xlQYY1738rjx\nxBgz0RjztDHmTWPMG8aY62I9pmgwxmQaYzYbY15tf58/jPWYoskYk2aMecUY82SsxxItxph3jTHb\njDFbjTFbYj2eeKP8Sh7Kr+QTL/nl6eU5Y8x0oA54wFr7Uc8OHEeMMQVAgbX2ZWNMDvASMMda+2aM\nh+YpY4wBhltr64wxGcA/geustc/HeGhRYYy5ASgBcq21F8d6PNFgjHkXKLHWVsZ6LPFI+ZU8lF/J\nJ17yy9OZJmvtM8D7Xh4z3lhry6y1L7f/vhZ4iyRcYdi2qWv/Y0b7V1I2wBljioCLgHtiPRaJHeVX\n8lB+SbSop2kQjDGTgFOBF2I7kuhon/LdClQAG6y1Sfk+gV8CNwKhWA8kyizwlDHmpfYVsCWFKb+S\nhvJrCKloGiBjzAjgT8C3rbU1sR5PNFhrg9baU2hbRXmaMSbpLlkYYy4GKqy1L8V6LEPg39r/e14I\nfKP9cpSkIOVXclB+DT0VTQPQfo38T8DD1trHYj2eaLPWVgNPAxfEeixRcBYwu/16+aPAp40xD8V2\nSNFhrd3f/msFsAaYFtsRSSwov5KK8muIqWhyqb3BcDnwlrX29liPJ1qMMWONMaPaf58FnAe8HdtR\nec9a+11rbZG1dhJtj9jYaK39UoyH5TljzPD2xl+MMcOB84GkvUtMwlN+JRfl19DzesmBlcBzwFRj\nzD5jzNVeHj9OnAVcSVtFv7X9a2asBxUFBcDTxpjXaHt+1wZrbdLezpoCxgP/NMa8CmwG/mKtXRfj\nMcUV5VdSUX4ll7jJL60ILiIiIuKALs+JiIiIOKCiSURERMQBFU0iIiIiDqhoEhEREXFARZOIiIiI\nAyqaRERERBxQ0SQiIiLigIomEREREQf+P7T3NvHBP6ZGAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1054690b8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from mlxtend.plotting import plot_decision_regions\n",
    "import matplotlib.gridspec as gridspec\n",
    "import itertools\n",
    "\n",
    "gs = gridspec.GridSpec(2, 2)\n",
    "\n",
    "fig = plt.figure(figsize=(10,8))\n",
    "\n",
    "for clf, lab, grd in zip([clf1, clf2, clf3, sclf], \n",
    "                         ['KNN', \n",
    "                          'Random Forest', \n",
    "                          'Naive Bayes',\n",
    "                          'StackingClassifier'],\n",
    "                          itertools.product([0, 1], repeat=2)):\n",
    "\n",
    "    clf.fit(X, y)\n",
    "    ax = plt.subplot(gs[grd[0], grd[1]])\n",
    "    fig = plot_decision_regions(X=X, y=y, clf=clf)\n",
    "    plt.title(lab)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 2 - Using Probabilities as Meta-Features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, the class-probabilities of the first-level classifiers can be used to train the meta-classifier (2nd-level classifier) by setting `use_probas=True`. If `average_probas=True`, the probabilities of the level-1 classifiers are averaged, if `average_probas=False`, the probabilities are stacked (recommended). For example, in a 3-class setting with 2 level-1 classifiers, these classifiers may make the following \"probability\" predictions for 1 training sample:\n",
    "\n",
    "- classifier 1: [0.2, 0.5, 0.3]\n",
    "- classifier 2: [0.3, 0.4, 0.4]\n",
    "\n",
    "If `average_probas=True`, the meta-features would be:\n",
    "\n",
    "- [0.25, 0.45, 0.35]\n",
    "\n",
    "In contrast, using `average_probas=False` results in k features where, k = [n_classes * n_classifiers], by stacking these level-1 probabilities:\n",
    "\n",
    "- [0.2, 0.5, 0.3, 0.3, 0.4, 0.4]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3-fold cross validation:\n",
      "\n",
      "Accuracy: 0.91 (+/- 0.01) [KNN]\n",
      "Accuracy: 0.91 (+/- 0.06) [Random Forest]\n",
      "Accuracy: 0.92 (+/- 0.03) [Naive Bayes]\n",
      "Accuracy: 0.94 (+/- 0.03) [StackingClassifier]\n"
     ]
    }
   ],
   "source": [
    "clf1 = KNeighborsClassifier(n_neighbors=1)\n",
    "clf2 = RandomForestClassifier(random_state=1)\n",
    "clf3 = GaussianNB()\n",
    "lr = LogisticRegression()\n",
    "sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],\n",
    "                          use_probas=True,\n",
    "                          average_probas=False,\n",
    "                          meta_classifier=lr)\n",
    "\n",
    "print('3-fold cross validation:\\n')\n",
    "\n",
    "for clf, label in zip([clf1, clf2, clf3, sclf], \n",
    "                      ['KNN', \n",
    "                       'Random Forest', \n",
    "                       'Naive Bayes',\n",
    "                       'StackingClassifier']):\n",
    "\n",
    "    scores = model_selection.cross_val_score(clf, X, y, \n",
    "                                              cv=3, scoring='accuracy')\n",
    "    print(\"Accuracy: %0.2f (+/- %0.2f) [%s]\" \n",
    "          % (scores.mean(), scores.std(), label))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 3 - Stacked Classification and GridSearch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To set up a parameter grid for scikit-learn's `GridSearch`, we simply provide the estimator's names in the parameter grid -- in the special case of the meta-regressor, we append the `'meta-'` prefix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.927 +/- 0.02 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.913 +/- 0.03 {'kneighborsclassifier__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.933 +/- 0.02 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.940 +/- 0.02 {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "Best parameters: {'kneighborsclassifier__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "Accuracy: 0.94\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.naive_bayes import GaussianNB \n",
    "from sklearn.ensemble import RandomForestClassifier\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "from mlxtend.classifier import StackingClassifier\n",
    "\n",
    "# Initializing models\n",
    "\n",
    "clf1 = KNeighborsClassifier(n_neighbors=1)\n",
    "clf2 = RandomForestClassifier(random_state=1)\n",
    "clf3 = GaussianNB()\n",
    "lr = LogisticRegression()\n",
    "sclf = StackingClassifier(classifiers=[clf1, clf2, clf3], \n",
    "                          meta_classifier=lr)\n",
    "\n",
    "params = {'kneighborsclassifier__n_neighbors': [1, 5],\n",
    "          'randomforestclassifier__n_estimators': [10, 50],\n",
    "          'meta-logisticregression__C': [0.1, 10.0]}\n",
    "\n",
    "grid = GridSearchCV(estimator=sclf, \n",
    "                    param_grid=params, \n",
    "                    cv=5,\n",
    "                    refit=True)\n",
    "grid.fit(X, y)\n",
    "\n",
    "cv_keys = ('mean_test_score', 'std_test_score', 'params')\n",
    "\n",
    "for r, _ in enumerate(grid.cv_results_['mean_test_score']):\n",
    "    print(\"%0.3f +/- %0.2f %r\"\n",
    "          % (grid.cv_results_[cv_keys[0]][r],\n",
    "             grid.cv_results_[cv_keys[1]][r] / 2.0,\n",
    "             grid.cv_results_[cv_keys[2]][r]))\n",
    "\n",
    "print('Best parameters: %s' % grid.best_params_)\n",
    "print('Accuracy: %.2f' % grid.best_score_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In case we are planning to use a regression algorithm multiple times, all we need to do is to add an additional number suffix in the parameter grid as shown below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.907 +/- 0.03 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.913 +/- 0.03 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.927 +/- 0.02 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.913 +/- 0.03 {'kneighborsclassifier-1__n_neighbors': 1, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.927 +/- 0.02 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.913 +/- 0.03 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 1, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 10}\n",
      "0.667 +/- 0.00 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 0.1, 'randomforestclassifier__n_estimators': 50}\n",
      "0.933 +/- 0.02 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 10}\n",
      "0.940 +/- 0.02 {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "Best parameters: {'kneighborsclassifier-1__n_neighbors': 5, 'kneighborsclassifier-2__n_neighbors': 5, 'meta-logisticregression__C': 10.0, 'randomforestclassifier__n_estimators': 50}\n",
      "Accuracy: 0.94\n"
     ]
    }
   ],
   "source": [
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "# Initializing models\n",
    "\n",
    "clf1 = KNeighborsClassifier(n_neighbors=1)\n",
    "clf2 = RandomForestClassifier(random_state=1)\n",
    "clf3 = GaussianNB()\n",
    "lr = LogisticRegression()\n",
    "sclf = StackingClassifier(classifiers=[clf1, clf1, clf2, clf3], \n",
    "                          meta_classifier=lr)\n",
    "\n",
    "params = {'kneighborsclassifier-1__n_neighbors': [1, 5],\n",
    "          'kneighborsclassifier-2__n_neighbors': [1, 5],\n",
    "          'randomforestclassifier__n_estimators': [10, 50],\n",
    "          'meta-logisticregression__C': [0.1, 10.0]}\n",
    "\n",
    "grid = GridSearchCV(estimator=sclf, \n",
    "                    param_grid=params, \n",
    "                    cv=5,\n",
    "                    refit=True)\n",
    "grid.fit(X, y)\n",
    "\n",
    "cv_keys = ('mean_test_score', 'std_test_score', 'params')\n",
    "\n",
    "for r, _ in enumerate(grid.cv_results_['mean_test_score']):\n",
    "    print(\"%0.3f +/- %0.2f %r\"\n",
    "          % (grid.cv_results_[cv_keys[0]][r],\n",
    "             grid.cv_results_[cv_keys[1]][r] / 2.0,\n",
    "             grid.cv_results_[cv_keys[2]][r]))\n",
    "\n",
    "print('Best parameters: %s' % grid.best_params_)\n",
    "print('Accuracy: %.2f' % grid.best_score_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note**\n",
    "\n",
    "The `StackingClassifier` also enables grid search over the `classifiers` argument. However, due to the current implementation of `GridSearchCV` in scikit-learn, it is not possible to search over both, differenct classifiers and classifier parameters at the same time. For instance, while the following parameter dictionary works\n",
    "\n",
    "    params = {'randomforestclassifier__n_estimators': [1, 100],\n",
    "    'classifiers': [(clf1, clf1, clf1), (clf2, clf3)]}\n",
    "    \n",
    "it will use the instance settings of `clf1`, `clf2`, and `clf3` and not overwrite it with the `'n_estimators'` settings from `'randomforestclassifier__n_estimators': [1, 100]`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 4 - Stacking of Classifiers that Operate on Different Feature Subsets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The different level-1 classifiers can be fit to different subsets of features in the training dataset. The following example illustrates how this can be done on a technical level using scikit-learn pipelines and the `ColumnSelector`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "StackingClassifier(average_probas=False,\n",
       "          classifiers=[Pipeline(steps=[('columnselector', ColumnSelector(cols=(0, 2))), ('logisticregression', LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
       "          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n",
       "          penalty='l2', random_state=None, solve...='l2', random_state=None, solver='liblinear', tol=0.0001,\n",
       "          verbose=0, warm_start=False))])],\n",
       "          meta_classifier=LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,\n",
       "          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,\n",
       "          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,\n",
       "          verbose=0, warm_start=False),\n",
       "          use_features_in_secondary=False, use_probas=False, verbose=0)"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.datasets import load_iris\n",
    "from mlxtend.classifier import StackingClassifier\n",
    "from mlxtend.feature_selection import ColumnSelector\n",
    "from sklearn.pipeline import make_pipeline\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "iris = load_iris()\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "pipe1 = make_pipeline(ColumnSelector(cols=(0, 2)),\n",
    "                      LogisticRegression())\n",
    "pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)),\n",
    "                      LogisticRegression())\n",
    "\n",
    "sclf = StackingClassifier(classifiers=[pipe1, pipe2], \n",
    "                          meta_classifier=LogisticRegression())\n",
    "\n",
    "sclf.fit(X, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "## StackingClassifier\n",
      "\n",
      "*StackingClassifier(classifiers, meta_classifier, use_probas=False, average_probas=False, verbose=0, use_features_in_secondary=False, store_train_meta_features=False, use_clones=True)*\n",
      "\n",
      "A Stacking classifier for scikit-learn estimators for classification.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `classifiers` : array-like, shape = [n_classifiers]\n",
      "\n",
      "    A list of classifiers.\n",
      "    Invoking the `fit` method on the `StackingClassifer` will fit clones\n",
      "    of these original classifiers that will\n",
      "    be stored in the class attribute\n",
      "    `self.clfs_`.\n",
      "\n",
      "- `meta_classifier` : object\n",
      "\n",
      "    The meta-classifier to be fitted on the ensemble of\n",
      "    classifiers\n",
      "\n",
      "- `use_probas` : bool (default: False)\n",
      "\n",
      "    If True, trains meta-classifier based on predicted probabilities\n",
      "    instead of class labels.\n",
      "\n",
      "- `average_probas` : bool (default: False)\n",
      "\n",
      "    Averages the probabilities as meta features if True.\n",
      "\n",
      "- `verbose` : int, optional (default=0)\n",
      "\n",
      "    Controls the verbosity of the building process.\n",
      "    - `verbose=0` (default): Prints nothing\n",
      "    - `verbose=1`: Prints the number & name of the regressor being fitted\n",
      "    - `verbose=2`: Prints info about the parameters of the\n",
      "    regressor being fitted\n",
      "    - `verbose>2`: Changes `verbose` param of the underlying regressor to\n",
      "    self.verbose - 2\n",
      "\n",
      "- `use_features_in_secondary` : bool (default: False)\n",
      "\n",
      "    If True, the meta-classifier will be trained both on the predictions\n",
      "    of the original classifiers and the original dataset.\n",
      "    If False, the meta-classifier will be trained only on the predictions\n",
      "    of the original classifiers.\n",
      "\n",
      "- `store_train_meta_features` : bool (default: False)\n",
      "\n",
      "    If True, the meta-features computed from the training data used\n",
      "    for fitting the meta-classifier stored in the\n",
      "    `self.train_meta_features_` array, which can be\n",
      "    accessed after calling `fit`.\n",
      "\n",
      "- `use_clones` : bool (default: True)\n",
      "\n",
      "    Clones the classifiers for stacking classification if True (default)\n",
      "    or else uses the original ones, which will be refitted on the dataset\n",
      "    upon calling the `fit` method. Hence, if use_clones=True, the original\n",
      "    input classifiers will remain unmodified upon using the\n",
      "    StackingClassifier's `fit` method.\n",
      "    Setting `use_clones=False` is\n",
      "    recommended if you are working with estimators that are supporting\n",
      "    the scikit-learn fit/predict API interface but are not compatible\n",
      "    to scikit-learn's `clone` function.\n",
      "\n",
      "**Attributes**\n",
      "\n",
      "- `clfs_` : list, shape=[n_classifiers]\n",
      "\n",
      "    Fitted classifiers (clones of the original classifiers)\n",
      "\n",
      "- `meta_clf_` : estimator\n",
      "\n",
      "    Fitted meta-classifier (clone of the original meta-estimator)\n",
      "\n",
      "- `train_meta_features` : numpy array, shape = [n_samples, n_classifiers]\n",
      "\n",
      "    meta-features for training data, where n_samples is the\n",
      "    number of samples\n",
      "    in training data and n_classifiers is the number of classfiers.\n",
      "\n",
      "**Examples**\n",
      "\n",
      "For usage examples, please see\n",
      "    [http://rasbt.github.io/mlxtend/user_guide/classifier/StackingClassifier/](http://rasbt.github.io/mlxtend/user_guide/classifier/StackingClassifier/)\n",
      "\n",
      "### Methods\n",
      "\n",
      "<hr>\n",
      "\n",
      "*fit(X, y)*\n",
      "\n",
      "Fit ensemble classifers and the meta-classifier.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "\n",
      "- `y` : array-like, shape = [n_samples] or [n_samples, n_outputs]\n",
      "\n",
      "    Target values.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `self` : object\n",
      "\n",
      "\n",
      "<hr>\n",
      "\n",
      "*fit_transform(X, y=None, **fit_params)*\n",
      "\n",
      "Fit to data, then transform it.\n",
      "\n",
      "Fits transformer to X and y with optional parameters fit_params\n",
      "and returns a transformed version of X.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : numpy array of shape [n_samples, n_features]\n",
      "\n",
      "    Training set.\n",
      "\n",
      "\n",
      "- `y` : numpy array of shape [n_samples]\n",
      "\n",
      "    Target values.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `X_new` : numpy array of shape [n_samples, n_features_new]\n",
      "\n",
      "    Transformed array.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*get_params(deep=True)*\n",
      "\n",
      "Return estimator parameter names for GridSearch support.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*predict(X)*\n",
      "\n",
      "Predict target values for X.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `labels` : array-like, shape = [n_samples] or [n_samples, n_outputs]\n",
      "\n",
      "    Predicted class labels.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*predict_meta_features(X)*\n",
      "\n",
      "Get meta-features of test-data.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : numpy array, shape = [n_samples, n_features]\n",
      "\n",
      "    Test vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `meta-features` : numpy array, shape = [n_samples, n_classifiers]\n",
      "\n",
      "    Returns the meta-features for test data.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*predict_proba(X)*\n",
      "\n",
      "Predict class probabilities for X.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : {array-like, sparse matrix}, shape = [n_samples, n_features]\n",
      "\n",
      "    Training vectors, where n_samples is the number of samples and\n",
      "    n_features is the number of features.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `proba` : array-like, shape = [n_samples, n_classes] or a list of                 n_outputs of such arrays if n_outputs > 1.\n",
      "\n",
      "    Probability for each class per sample.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*score(X, y, sample_weight=None)*\n",
      "\n",
      "Returns the mean accuracy on the given test data and labels.\n",
      "\n",
      "In multi-label classification, this is the subset accuracy\n",
      "which is a harsh metric since you require for each sample that\n",
      "each label set be correctly predicted.\n",
      "\n",
      "**Parameters**\n",
      "\n",
      "- `X` : array-like, shape = (n_samples, n_features)\n",
      "\n",
      "    Test samples.\n",
      "\n",
      "\n",
      "- `y` : array-like, shape = (n_samples) or (n_samples, n_outputs)\n",
      "\n",
      "    True labels for X.\n",
      "\n",
      "\n",
      "- `sample_weight` : array-like, shape = [n_samples], optional\n",
      "\n",
      "    Sample weights.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "- `score` : float\n",
      "\n",
      "    Mean accuracy of self.predict(X) wrt. y.\n",
      "\n",
      "<hr>\n",
      "\n",
      "*set_params(**params)*\n",
      "\n",
      "Set the parameters of this estimator.\n",
      "\n",
      "The method works on simple estimators as well as on nested objects\n",
      "(such as pipelines). The latter have parameters of the form\n",
      "``<component>__<parameter>`` so that it's possible to update each\n",
      "component of a nested object.\n",
      "\n",
      "**Returns**\n",
      "\n",
      "self\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "with open('../../api_modules/mlxtend.classifier/StackingClassifier.md', 'r') as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "toc": {
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
